### Implement MetricsInterceptor Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/api-reference-core-interfaces.md Example implementation of HandlerInterceptor to record execution metrics for jobs. ```java @Component public class MetricsInterceptor implements HandlerInterceptor { @Override public boolean preHandle(JobContext context) { context.setAttribute("startTime", System.currentTimeMillis()); return true; } @Override public void postHandle(JobContext context, Object result) { long duration = System.currentTimeMillis() - (Long) context.getAttribute("startTime"); metricsService.recordJobExecution( context.getJobId(), duration, true ); } @Override public void afterCompletion(JobContext context, Exception ex) { if (ex != null) { metricsService.recordJobFailure(context.getJobId(), ex); } } } ``` -------------------------------- ### Cron Expression Examples Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/quick-reference.md Commonly used cron expressions for scheduling jobs. ```text * * * * * (Every minute) 0 * * * * (Every hour) */15 * * * * (Every 15 minutes) 0 9 * * * (Daily at 9 AM) 0 9 * * MON-FRI (Weekdays at 9 AM) 0 0 1 * * (First day of month) 0 0 * * 0 (Every Sunday) 0 0 * * 1 (Every Monday) 30 2 * * * (Daily at 2:30 AM) 0 0 * * * (Daily at midnight) ``` -------------------------------- ### Implement Map Phase Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/api-reference-client-annotations.md Example of using @MapExecutor to partition data for parallel processing. ```java @Component public class DataProcessingHandler { @JobExecutor(name = "dataPipeline") @MapExecutor public List mapData(JobContext jobContext) { // Fetch and partition data List rawData = dataSource.fetchBatch(); return rawData.stream() .map(raw -> new DataItem(raw.getId(), raw.getValue())) .collect(Collectors.toList()); } } ``` -------------------------------- ### Complete application.yml Configuration Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/configuration.md A full example of the Snail-Job configuration block within a Spring application.yml file. ```yaml spring: application: name: my-service datasource: url: jdbc:mysql://localhost:3306/mydb username: root password: password snail-job: # Client identity namespace: production group: my_service_group token: abc123def456xyz789 # Network host: 10.0.1.100 port: 17889 # Server location server: host: snail-job.internal.example.com port: 17888 # RPC protocol rpcType: GRPC # Custom labels labels: env: production region: us-east-1 team: platform # Job execution httpResponse: code: 200 field: code responseType: json # Retry behavior retry: reportSlidingWindow: totalThreshold: 100 windowTotalThreshold: 300 duration: 10 chronoUnit: SECONDS dispatcherThreadPool: corePoolSize: 32 maximumPoolSize: 64 keepAliveTime: 1 timeUnit: SECONDS queueCapacity: 20000 # Log reporting logSlidingWindow: totalThreshold: 50 windowTotalThreshold: 150 duration: 5 chronoUnit: SECONDS # RPC tuning clientRpc: maxInboundMessageSize: 10485760 keepAliveTime: 30s keepAliveTimeout: 10s permitKeepAliveTime: 5m idleTimeout: 5m clientTp: corePoolSize: 16 maximumPoolSize: 32 keepAliveTime: 1 timeUnit: SECONDS queueCapacity: 10000 serverRpc: maxInboundMessageSize: 10485760 keepAliveTime: 2h keepAliveTimeout: 20s permitKeepAliveTime: 5m dispatcherTp: corePoolSize: 16 maximumPoolSize: 32 keepAliveTime: 1 timeUnit: SECONDS queueCapacity: 10000 # OpenAPI openapi: host: snail-job.internal.example.com port: 8080 https: false prefix: snail-job # Email alarms mail: enabled: true from: alerts@example.com host: smtp.example.com port: 587 username: alert-user password: smtp-password ``` -------------------------------- ### IJobExecutor Implementation Example Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/api-reference-core-interfaces.md A standard implementation of IJobExecutor for processing orders with sharding support. ```java @Component public class OrderProcessingExecutor implements IJobExecutor { @Autowired private OrderService orderService; @Override public void jobExecute(JobContext jobContext) { Long jobId = jobContext.getJobId(); Integer shardingIndex = jobContext.getShardingIndex(); Integer shardingTotal = jobContext.getShardingTotal(); // Process shard List orders = orderService.getForShard(shardingIndex, shardingTotal); for (Order order : orders) { try { processOrder(order); } catch (Exception e) { logger.error("Failed to process order {}", order.getId(), e); // Decide: rethrow to fail job or continue with next order throw new RuntimeException("Order processing failed", e); } } } private void processOrder(Order order) { // Business logic } } ``` -------------------------------- ### Configure SnailJob via application.yml Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/types.md Example YAML configuration for setting up the SnailJob client properties in a Spring Boot application. ```yaml snail-job: namespace: my_tenant group: order_service token: abc123def456 host: 10.0.1.100 port: 17889 rpcType: GRPC labels: env: production region: us-east-1 server: host: snail-job-server.internal port: 17888 retry: reportSlidingWindow: totalThreshold: 100 windowTotalThreshold: 300 duration: 10 chronoUnit: SECONDS openapi: host: snail-job-server.internal port: 8080 prefix: snail-job ``` -------------------------------- ### GET /snail-job/openapi/v1/workflow Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/api-reference-openapi-endpoints.md Retrieves workflow details by ID. ```APIDOC ## GET /snail-job/openapi/v1/workflow ### Description Retrieves workflow details by ID. ### Method GET ### Endpoint /snail-job/openapi/v1/workflow ### Parameters #### Query Parameters - **id** (Long) - Required - Workflow ID ### Response #### Success Response (200) - **workflowDetail** (WorkflowDetailApiResponse) - Workflow details ``` -------------------------------- ### Implement Reduce Phase Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/api-reference-client-annotations.md Example of using @ReduceExecutor to aggregate results from the map phase. ```java @Component public class DataProcessingHandler { @JobExecutor(name = "dataPipeline") @ReduceExecutor public void reduceData(JobContext jobContext) { // jobContext.getTaskList() contains results from map phase List results = jobContext.getTaskList(); // Aggregate results Map aggregated = results.stream() .filter(r -> r instanceof DataItem) .map(r -> (DataItem) r) .collect(Collectors.groupingBy( DataItem::getCategory, Collectors.summingLong(DataItem::getCount) )); persistAggregation(aggregated); } } ``` -------------------------------- ### Handle SnailJobClientException in Consumer Code Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/errors.md Example of catching and logging client-side exceptions during executor registration. ```java try { snailJobClient.registerExecutor(handler); } catch (SnailJobClientException e) { logger.error("Client operation failed: {}", e.getMessage(), e); // Implement fallback or circuit breaker } ``` -------------------------------- ### MergeReduceExecutor Usage Example Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/api-reference-client-annotations.md Example of applying @MergeReduceExecutor to a job handler method to perform combined map-reduce logic. ```java @Component public class ReportJobHandler { @JobExecutor(name = "dailyReportGeneration") @MergeReduceExecutor public void generateReport(JobContext jobContext) { // Combined map-reduce: fetch, transform, and aggregate in one method LocalDate reportDate = LocalDate.now().minusDays(1); List transactions = transactionService.fetchByDate(reportDate); Map dailySummary = transactions.stream() .collect(Collectors.groupingBy( Transaction::getMerchantId, Collectors.reducing( BigDecimal.ZERO, Transaction::getAmount, BigDecimal::add ) )); reportService.saveDailyReport(reportDate, dailySummary); } } ``` -------------------------------- ### RetryOperations Usage Example Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/api-reference-core-interfaces.md Demonstrates injecting and using RetryOperations within a Spring service. ```java @Service public class PaymentService { @Autowired private RetryOperations retryOperations; public PaymentResult processPayment(String orderId, BigDecimal amount) throws Exception { return retryOperations.execute( "process_payment", () -> { // This callable is executed with retry logic return chargeCard(orderId, amount); } ); } } ``` -------------------------------- ### GET /snail-job/openapi/v1/workflow/batch Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/api-reference-openapi-endpoints.md Retrieves details for a specific workflow batch. ```APIDOC ## GET /snail-job/openapi/v1/workflow/batch ### Description Retrieves workflow batch details. ### Method GET ### Endpoint /snail-job/openapi/v1/workflow/batch ### Parameters #### Query Parameters - **id** (Long) - Required - Batch ID ### Response #### Success Response (200) - **JobBatchApiResponse** (object) - The workflow batch details. ``` -------------------------------- ### CustomRetryExecutor Implementation Example Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/api-reference-core-interfaces.md A concrete implementation of the RetryExecutor interface demonstrating how to configure retry attempts, intervals, and Guava retry strategies. ```java public class CustomRetryExecutor implements RetryExecutor { @Override public RetryerInfo getRetryerInfo() { return new RetryerInfo() .setAttempt(3) .setInterval(2000); } @Override public Object execute(Object... params) { // Invoke method with params using configured retry strategy return null; } @Override public Retryer build(RetryExecutorParameter parameter) { // Build Guava Retryer with exponential backoff return RetryerBuilder.newBuilder() .retryIfException() .withWaitStrategy(WaitStrategies.exponentialWait(100, TimeUnit.MILLISECONDS)) .withStopStrategy(StopStrategies.stopAfterAttempt(3)) .build(); } @Override public V call(Retryer retryer, Callable callable, Consumer retryError, Consumer retrySuccess) throws Exception { try { return retryer.call(callable); } catch (Exception e) { retryError.accept(e); throw e; } } } ``` -------------------------------- ### GET /snail-job/openapi/v1/job/batch Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/api-reference-openapi-endpoints.md Retrieves details for a specific job batch. ```APIDOC ## GET /snail-job/openapi/v1/job/batch ### Description Retrieves job batch (execution batch) details. ### Method GET ### Endpoint /snail-job/openapi/v1/job/batch ### Parameters #### Query Parameters - **id** (Long) - Required - Job batch ID ### Response #### Success Response (200) - **id** (Long) - Batch ID - **jobId** (Long) - Job ID - **triggerTime** (Long) - When batch was triggered - **taskCount** (Integer) - Total tasks in batch - **successCount** (Integer) - Completed successfully - **failedCount** (Integer) - Failed tasks ``` -------------------------------- ### GET /snail-job/openapi/v1/job/exists Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/api-reference-openapi-endpoints.md Checks if a job exists in the system by its ID. ```APIDOC ## GET /snail-job/openapi/v1/job/exists ### Description Checks if a job exists by ID. ### Method GET ### Endpoint /snail-job/openapi/v1/job/exists ### Parameters #### Query Parameters - **id** (Long) - Required - Job ID ### Response #### Success Response (200) - **exists** (Boolean) - Whether job exists ``` -------------------------------- ### Implement Custom IdempotentIdGenerate Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/api-reference-core-interfaces.md Example of a custom implementation for order processing and its application via the @Retryable annotation. ```java public class OrderIdempotentIdGenerate implements IdempotentIdGenerate { @Override public String generate(Object... args) { // For payment operations, use order ID as idempotent key if (args.length > 0 && args[0] instanceof Order) { Order order = (Order) args[0]; return "order_" + order.getId(); } // Fallback to hash of all args return DigestUtils.md5Hex(ObjectUtils.toString(args)); } } // Usage: @Retryable( scene = "order_payment", idempotentId = OrderIdempotentIdGenerate.class ) public void processOrder(Order order) { paymentService.charge(order); } ``` -------------------------------- ### GET /snail-job/openapi/v1/job/bizId Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/api-reference-openapi-endpoints.md Retrieves job details using a business identifier. ```APIDOC ## GET /snail-job/openapi/v1/job/bizId ### Description Retrieves job by business ID. ### Method GET ### Endpoint /snail-job/openapi/v1/job/bizId ### Parameters #### Query Parameters - **bizId** (String) - Required - Business identifier ### Response #### Success Response (200) - **response** (JobApiResponse) - Job details ``` -------------------------------- ### Custom ExecutorMethod Implementation Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/api-reference-core-interfaces.md Example of implementing custom retry logic and applying it via the @Retryable annotation. ```java public class PaymentRetryMethod implements ExecutorMethod { @Override public Object execute(Object... args) { String orderId = (String) args[0]; BigDecimal amount = (BigDecimal) args[1]; // Custom retry logic - e.g., verify payment before retrying if (hasAlreadyCharged(orderId)) { return new PaymentResult(true, "Already charged"); // Skip retry } // Invoke actual payment with fallback try { return primaryGateway.charge(orderId, amount); } catch (Exception e) { return fallbackGateway.charge(orderId, amount); } } private boolean hasAlreadyCharged(String orderId) { return paymentDao.findByOrderId(orderId) != null; } } // Usage: @Retryable( scene = "process_payment", retryMethod = PaymentRetryMethod.class ) public PaymentResult charge(String orderId, BigDecimal amount) { return gateway.charge(orderId, amount); } ``` -------------------------------- ### Monitor Jobs with Interceptors Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/quick-reference.md Implementing HandlerInterceptor to track job lifecycle events like start, success, and failure. ```java @Component public class JobMetrics implements HandlerInterceptor { @Override public boolean preHandle(JobContext context) { metrics.recordJobStart(context.getJobId()); return true; } @Override public void postHandle(JobContext context, Object result) { metrics.recordJobSuccess(context.getJobId()); } @Override public void afterCompletion(JobContext context, Exception ex) { if (ex != null) metrics.recordJobFailure(context.getJobId(), ex); } } ``` -------------------------------- ### GET /snail-job/openapi/v1/job Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/api-reference-openapi-endpoints.md Retrieves detailed information about a specific job using its system-generated ID. ```APIDOC ## GET /snail-job/openapi/v1/job ### Description Retrieves job details by ID. ### Method GET ### Endpoint /snail-job/openapi/v1/job ### Parameters #### Query Parameters - **id** (Long) - Required - Job ID ### Response #### Success Response (200) - **id** (Long) - Job ID - **jobName** (String) - Job name - **groupName** (String) - Group name - **executorInfo** (String) - Executor identifier or URL - **jobStatus** (Integer) - Current status (0/1) - **triggerType** (Integer) - Trigger type - **triggerInterval** (String) - Interval/cron expression - **description** (String) - Job description ``` -------------------------------- ### OpenAPI Error Response Examples Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/errors.md Standardized JSON error formats for various HTTP status codes returned by the API. ```json { "code": "VALIDATION_ERROR", "message": "jobName cannot be null", "timestamp": 1720737600000, "path": "/snail-job/openapi/v1/job" } ``` ```json { "code": "UNAUTHORIZED", "message": "Invalid or missing authentication token", "timestamp": 1720737600000, "path": "/snail-job/openapi/v1/job" } ``` ```json { "code": "RESOURCE_NOT_FOUND", "message": "Job with id 123 not found", "timestamp": 1720737600000, "path": "/snail-job/openapi/v1/job" } ``` ```json { "code": "INTERNAL_SERVER_ERROR", "message": "Database connection failed", "timestamp": 1720737600000, "path": "/snail-job/openapi/v1/job" } ``` -------------------------------- ### Implement a job handler with @JobExecutor Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/api-reference-client-annotations.md Example of using @JobExecutor to register a method as a task executor, including access to JobContext for sharding information. ```java @Component public class OrderJobHandler { @JobExecutor(name = "orderProcessing") public void handleOrderProcessing(JobContext jobContext) { Long jobId = jobContext.getJobId(); String groupName = jobContext.getGroupName(); Integer shardingIndex = jobContext.getShardingIndex(); Integer shardingTotal = jobContext.getShardingTotal(); // Process job with sharding awareness List orders = orderService.getShardedOrders(shardingIndex, shardingTotal); for (Order order : orders) { processOrder(order); } } } ``` -------------------------------- ### Handle Job Execution Errors Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/errors.md Example of wrapping job logic in a try-catch block to throw SnailJobInnerExecutorException when processing fails. ```java @JobExecutor(name = "processOrders") public void execute(JobContext context) { try { // Long-running operation processOrders(context); } catch (Exception e) { // Must handle or throw appropriately logger.error("Job failed", e); throw new SnailJobInnerExecutorException("Processing failed", e); } } ``` -------------------------------- ### Implement and Use RetryCondition Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/api-reference-core-interfaces.md Examples of custom RetryCondition implementations for HTTP status codes and API responses, along with usage in a @Retryable annotation. ```java public class HttpStatusRetryCondition implements RetryCondition { @Override public boolean needRetry(Object result) { if (result == null) return false; if (!(result instanceof HttpResponse)) return false; HttpResponse response = (HttpResponse) result; int status = response.getStatusCode(); // Retry on 5xx errors or specific 4xx errors return status >= 500 || status == 408 || status == 429; } } public class ApiResponseRetryCondition implements RetryCondition { @Override public boolean needRetry(Object result) { if (!(result instanceof ApiResponse)) return false; ApiResponse response = (ApiResponse) result; // Retry if server indicates temporary unavailability return response.getErrorCode() == ErrorCode.TEMPORARY_UNAVAILABLE; } } // Usage: @Retryable( scene = "api_call", retryIfResult = HttpStatusRetryCondition.class, localTimes = 2 ) public HttpResponse callExternalApi(String endpoint) { return httpClient.get(endpoint); } ``` -------------------------------- ### Configure SnailJob via Environment Variables Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/configuration.md Set configuration parameters using uppercase environment variables with underscores. ```bash export SNAIL_JOB_GROUP=my_service_group export SNAIL_JOB_TOKEN=abc123def456xyz789 export SNAIL_JOB_SERVER_HOST=snail-job.internal.example.com export SNAIL_JOB_SERVER_PORT=17888 export SNAIL_JOB_NAMESPACE=production ``` -------------------------------- ### Create a Job via OpenAPI Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/quick-reference.md Use the REST API to programmatically create a new job definition. ```bash curl -X POST http://localhost:8080/snail-job/openapi/v1/job \ -H "Content-Type: application/json" \ -d '{ "groupName": "demo", "jobName": "demo_job", "executorType": 2, "executorInfo": "demoJob", "triggerType": 2, "triggerInterval": "300", "blockStrategy": 3, "executorTimeout": 60, "maxRetryTimes": 1, "retryInterval": 30, "taskType": 1, "parallelNum": 1, "routeKey": 1 }' ``` -------------------------------- ### GET /snail-job/openapi/v1/retry Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/api-reference-openapi-endpoints.md Retrieves the details of a specific retry task by its ID. ```APIDOC ## GET /snail-job/openapi/v1/retry ### Description Retrieves retry task details by ID. ### Method GET ### Endpoint /snail-job/openapi/v1/retry ### Parameters #### Query Parameters - **id** (Long) - Required - Retry task ID ### Response #### Success Response (200) - **id** (Long) - Retry task ID - **scene** (String) - Retry scenario - **bizNo** (String) - Business number - **status** (Integer) - Retry status - **errorMsg** (String) - Last error message - **retryCount** (Integer) - Current retry count ``` -------------------------------- ### Configure SnailJob RPC and Retry Settings Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/errors.md YAML configuration for adjusting gRPC keep-alive intervals and retry reporting windows. ```yaml snail-job: clientRpc: keepAliveTime: 30s # gRPC keep-alive ping interval keepAliveTimeout: 10s # Timeout for ping response retry: reportSlidingWindow: duration: 10 # Report retry data every 10 seconds ``` -------------------------------- ### POST /snail-job/openapi/v1/workflow/batch Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/api-reference-openapi-endpoints.md Creates a new workflow batch. ```APIDOC ## POST /snail-job/openapi/v1/workflow/batch ### Description Creates a new workflow batch (collection of workflow executions). ### Method POST ### Endpoint /snail-job/openapi/v1/workflow/batch ### Request Body - **WorkflowBatchApiRequest** (object) - Required - The workflow batch creation request object. ### Response #### Success Response (200) - **batchId** (Long) - The ID of the created workflow batch. ``` -------------------------------- ### Define Workflow via OpenAPI Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/advanced-patterns.md Use this POST request to register a new workflow definition with the SnailJob server. ```bash curl -X POST http://localhost:8080/snail-job/openapi/v1/workflow \ -H "Authorization: Bearer token" \ -d '{ "groupName": "ecommerce", "workflowName": "order_fulfillment_pipeline", "triggerType": 2, "triggerInterval": "300", "description": "Process orders -> Reserve inventory -> Create shipment -> Update tracking" }' ``` -------------------------------- ### Configure SnailJob Environment Variables Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/quick-reference.md Set these environment variables to define group, token, namespace, and network connectivity for the SnailJob client. ```bash # Core export SNAIL_JOB_GROUP=my_group export SNAIL_JOB_TOKEN=my_token export SNAIL_JOB_NAMESPACE=my_namespace # Server export SNAIL_JOB_SERVER_HOST=snail-job.example.com export SNAIL_JOB_SERVER_PORT=17888 # Network export SNAIL_JOB_HOST=10.0.1.100 export SNAIL_JOB_PORT=17889 ``` -------------------------------- ### Bootstrap SnailJob Application Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/quick-reference.md Configures the Spring Boot application to enable SnailJob and defines the server connection settings. ```java @SpringBootApplication @EnableSnailJob(group = "service_name") public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ``` ```yaml snail-job: group: service_name server: host: snail-job-server port: 17888 ``` -------------------------------- ### Configure SnailJob Client Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/README.md Define the group name and server connection details in the application configuration file. ```yaml snail-job: group: my_service_group server: host: snail-job-server.example.com port: 17888 ``` -------------------------------- ### Catching SnailJobCommonException Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/errors.md Example of catching general SnailJobCommonException during service execution to handle validation or state errors. ```java try { snailJobService.validateAndExecute(request); } catch (SnailJobCommonException e) { logger.error("Operation failed due to common error: {}", e.getMessage()); // Determine if operation should retry or fail fast } ``` -------------------------------- ### POST /snail-job/openapi/v1/workflow Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/api-reference-openapi-endpoints.md Creates a new workflow definition. ```APIDOC ## POST /snail-job/openapi/v1/workflow ### Description Creates a new workflow definition. ### Method POST ### Endpoint /snail-job/openapi/v1/workflow ### Parameters #### Request Body - **workflowName** (String) - Required - Workflow name - **groupName** (String) - Required - Group name - **triggerType** (Integer) - Required - Trigger type - **triggerInterval** (String) - Required - Interval/cron - **description** (String) - Optional - Workflow description ### Response #### Success Response (200) - **workflowId** (Long) - Created workflow ID ``` -------------------------------- ### POST /snail-job/openapi/v1/job/bizId Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/api-reference-openapi-endpoints.md Creates a new job using a business-unique identifier. ```APIDOC ## POST /snail-job/openapi/v1/job/bizId ### Description Creates a new job identified by bizId instead of system-generated ID. ### Method POST ### Endpoint /snail-job/openapi/v1/job/bizId ### Parameters #### Request Body - **bizId** (String) - Required - Business-unique identifier ### Response #### Success Response (200) - **response** (Long) - Internal job ID ``` -------------------------------- ### Configure HTTP Executor Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/quick-reference.md Define HTTP response handling and job execution parameters. ```yaml snail-job: httpResponse: code: 200 # Expected success status field: code # JSON field with status responseType: json # Response type: json or text ``` ```json { "executorType": 1, "executorInfo": "http://worker:8080/job/execute", "argsStr": "{\"key\":\"value\"}", "argsType": 2 } ``` -------------------------------- ### Create Job via OpenAPI Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/README.md Submit a POST request to the SnailJob OpenAPI endpoint to register a new job definition. ```bash curl -X POST http://localhost:8080/snail-job/openapi/v1/job \ -H "Authorization: Bearer TOKEN" \ -H "Content-Type: application/json" \ -d '{ "groupName": "my_service_group", "jobName": "process_batch", "executorInfo": "myJobName", "triggerType": 3, "triggerInterval": "0 * * * *", "blockStrategy": 3, "executorTimeout": 300, "maxRetryTimes": 2, "retryInterval": 60, "taskType": 1, "parallelNum": 1, "executorType": 2, "routeKey": 1 }' ``` -------------------------------- ### Implement Batch Processing in Java Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/advanced-patterns.md Use this pattern to process large datasets in smaller chunks to prevent memory overflow. Ensure the batch size is tuned based on the available heap memory. ```java @Component public class OptimizedBatchProcessor { @JobExecutor(name = "batchProcessor") public void processBatch(JobContext context) { Integer batchSize = 100; List items = fetchItems(context); // Process in smaller batches to avoid memory issues for (int i = 0; i < items.size(); i += batchSize) { int end = Math.min(i + batchSize, items.size()); List batch = items.subList(i, end); try { processBatch(batch); } catch (Exception e) { logger.error("Batch {} failed", i / batchSize, e); // Continue with next batch or fail fast } } } private void processBatch(List batch) { // Bulk insert, update, or API call database.insertBatch(batch); } } ``` -------------------------------- ### Create a new scheduled job via cURL Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/api-reference-openapi-endpoints.md Sends a POST request to register a new job with specific execution and trigger configurations. ```bash curl -X POST http://localhost:8080/snail-job/openapi/v1/job \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_TOKEN" \ -d '{ "groupName": "order_service", "jobName": "process_orders_hourly", "jobStatus": 1, "routeKey": 1, "executorType": 1, "executorInfo": "http://worker-1:8080/job/process", "triggerType": 3, "triggerInterval": "0 * * * *", "blockStrategy": 3, "executorTimeout": 300, "maxRetryTimes": 3, "retryInterval": 60, "taskType": 1, "parallelNum": 1, "description": "Process pending orders every hour", "labels": "{\"env\":\"prod\",\"team\":\"platform\"}" }' ``` -------------------------------- ### Handle OpenAPI Authentication Errors Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/errors.md Demonstrates the difference between unauthorized and authorized requests to the SnailJob OpenAPI. ```bash # Wrong: Missing token curl http://localhost:8080/snail-job/openapi/v1/job \ -d '{"groupName":"..."}' # Response: 401 UNAUTHORIZED # Correct: Include token curl http://localhost:8080/snail-job/openapi/v1/job \ -H "Authorization: Bearer valid-token-here" \ -d '{"groupName":"..."}' ``` -------------------------------- ### POST /snail-job/openapi/v1/workflow/trigger Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/api-reference-openapi-endpoints.md Immediately triggers a workflow execution. ```APIDOC ## POST /snail-job/openapi/v1/workflow/trigger ### Description Immediately triggers a workflow execution. ### Method POST ### Endpoint /snail-job/openapi/v1/workflow/trigger ### Parameters #### Request Body - **workflowId** (Long) - Required - Workflow ID ### Response #### Success Response (200) - **result** (Boolean) ``` -------------------------------- ### Define Optional Job Configuration Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/quick-reference.md JSON schema for optional job fields such as status, arguments, and metadata. ```json { "jobStatus": 1, // 0=disabled, 1=enabled "argsStr": "param_value", // Job parameters "argsType": 2, // 1=text, 2=json "bizId": "business_id", // For bizId-based operations "description": "...", "labels": "{\"key\":\"value\"}", "notifyIds": [1, 2, 3], "ownerId": 123 } ``` -------------------------------- ### POST /snail-job/openapi/v1/job Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/README.md Creates a new job within the SnailJob system using the provided configuration parameters. ```APIDOC ## POST /snail-job/openapi/v1/job ### Description Creates a new job in the SnailJob system. ### Method POST ### Endpoint http://localhost:8080/snail-job/openapi/v1/job ### Request Body - **groupName** (string) - Required - The service group name. - **jobName** (string) - Required - The name of the job. - **executorInfo** (string) - Required - The executor identifier. - **triggerType** (integer) - Required - The type of trigger. - **triggerInterval** (string) - Required - The cron expression or interval. - **blockStrategy** (integer) - Required - The strategy for blocking. - **executorTimeout** (integer) - Required - Timeout in seconds. - **maxRetryTimes** (integer) - Required - Maximum number of retries. - **retryInterval** (integer) - Required - Interval between retries in seconds. - **taskType** (integer) - Required - The type of task. - **parallelNum** (integer) - Required - Number of parallel executions. - **executorType** (integer) - Required - The type of executor. - **routeKey** (integer) - Required - The routing key. ### Request Example { "groupName": "my_service_group", "jobName": "process_batch", "executorInfo": "myJobName", "triggerType": 3, "triggerInterval": "0 * * * *", "blockStrategy": 3, "executorTimeout": 300, "maxRetryTimes": 2, "retryInterval": 60, "taskType": 1, "parallelNum": 1, "executorType": 2, "routeKey": 1 } ``` -------------------------------- ### Configure Snail-Job application.properties Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/configuration.md Defines the full set of configuration properties for a Snail-Job client, including network, RPC, retry, and alarm settings. ```properties # Client identity snail-job.namespace=production snail-job.group=my_service_group snail-job.token=abc123def456xyz789 # Network snail-job.host=10.0.1.100 snail-job.port=17889 # Server location snail-job.server.host=snail-job.internal.example.com snail-job.server.port=17888 # RPC protocol snail-job.rpcType=GRPC # Custom labels snail-job.labels.env=production snail-job.labels.region=us-east-1 snail-job.labels.team=platform # Job execution snail-job.httpResponse.code=200 snail-job.httpResponse.field=code snail-job.httpResponse.responseType=json # Retry behavior snail-job.retry.reportSlidingWindow.totalThreshold=100 snail-job.retry.reportSlidingWindow.windowTotalThreshold=300 snail-job.retry.reportSlidingWindow.duration=10 snail-job.retry.reportSlidingWindow.chronoUnit=SECONDS snail-job.retry.dispatcherThreadPool.corePoolSize=32 snail-job.retry.dispatcherThreadPool.maximumPoolSize=64 snail-job.retry.dispatcherThreadPool.keepAliveTime=1 snail-job.retry.dispatcherThreadPool.timeUnit=SECONDS snail-job.retry.dispatcherThreadPool.queueCapacity=20000 # Log reporting snail-job.logSlidingWindow.totalThreshold=50 snail-job.logSlidingWindow.windowTotalThreshold=150 snail-job.logSlidingWindow.duration=5 snail-job.logSlidingWindow.chronoUnit=SECONDS # RPC tuning snail-job.clientRpc.maxInboundMessageSize=10485760 snail-job.clientRpc.keepAliveTime=30s snail-job.clientRpc.keepAliveTimeout=10s snail-job.clientRpc.permitKeepAliveTime=5m snail-job.clientRpc.idleTimeout=5m # OpenAPI snail-job.openapi.host=snail-job.internal.example.com snail-job.openapi.port=8080 snail-job.openapi.https=false snail-job.openapi.prefix=snail-job # Email alarms snail-job.mail.enabled=true snail-job.mail.from=alerts@example.com snail-job.mail.host=smtp.example.com snail-job.mail.port=587 snail-job.mail.username=alert-user snail-job.mail.password=smtp-password ``` -------------------------------- ### Implement Fallback Retry Pattern in Java Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/advanced-patterns.md Defines a secondary data source fallback strategy for resilient data fetching. ```java public class FallbackRetryMethod implements ExecutorMethod { @Autowired private PrimaryDataSource primary; @Autowired private FallbackDataSource fallback; @Override public Object execute(Object... args) { try { return primary.fetch((String) args[0]); } catch (Exception primaryError) { logger.warn("Primary data source failed, using fallback", primaryError); try { return fallback.fetch((String) args[0]); } catch (Exception fallbackError) { throw new DataFetchException("Both primary and fallback failed", fallbackError); } } } } @Retryable( scene = "resilient_data_fetch", retryMethod = FallbackRetryMethod.class ) public Data fetchDataWithFallback(String query) { // Will try primary, fallback, then retry return dataService.query(query); } ``` -------------------------------- ### POST /snail-job/openapi/v1/job/trigger Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/api-reference-openapi-endpoints.md Immediately triggers a job execution. ```APIDOC ## POST /snail-job/openapi/v1/job/trigger ### Description Immediately triggers a job execution. ### Method POST ### Endpoint /snail-job/openapi/v1/job/trigger ### Request Body - **jobId** (Long) - Required - Job ID to trigger ### Response #### Success Response (200) - **result** (Boolean) - True if triggered successfully ``` -------------------------------- ### Configure Map-Reduce Job Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/advanced-patterns.md JSON configuration for defining a map-reduce job, including executor type, trigger intervals, and retry policies. ```json { "groupName": "analytics_service", "jobName": "daily_report_generation", "executorType": 2, "executorInfo": "reportJobHandler", "taskType": 4, "triggerInterval": "0 2 * * *", "triggerType": 3, "blockStrategy": 1, "executorTimeout": 1800, "maxRetryTimes": 1, "retryInterval": 300 } ``` -------------------------------- ### Enable SnailJob in Spring Boot Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/README.md Annotate the main application class with @EnableSnailJob to initialize the client within a Spring Boot context. ```java @SpringBootApplication @EnableSnailJob(group = "my_service_group") public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ``` -------------------------------- ### Define Cron Expressions Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/configuration.md Use these patterns for triggerType=3 to schedule tasks based on cron syntax. ```text 0 0 * * * - Daily at midnight 0 * * * * - Every hour at minute 0 */15 * * * * - Every 15 minutes 0 9 * * MON-FRI - Weekdays at 9 AM 0 0 1 * * - First day of month 0 0 * * 0 - Every Sunday ``` -------------------------------- ### Synchronous Reporting with Callback Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/api-reference-client-annotations.md Configures synchronous server reporting and a custom callback for handling retry completion events. ```java @Retryable( scene = "order_fulfillment", async = false, timeout = 30000, unit = TimeUnit.MILLISECONDS, retryCompleteCallback = OrderRetryCallback.class ) public void fulfillOrder(Long orderId) { fulfillmentService.process(orderId); } public class OrderRetryCallback implements RetryCompleteCallback { @Override public void retryComplete(RetryContext context) { if (context.isSuccess()) { notificationService.sendSuccess(context.getBizNo()); } else { notificationService.sendFailure(context.getBizNo()); } } } ``` -------------------------------- ### Unit Test with Mockito Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/advanced-patterns.md Uses MockitoJUnitRunner to isolate the processor logic by mocking the OrderService dependency. ```java @RunWith(MockitoJUnitRunner.class) public class OrderProcessorTest { @Mock private OrderService orderService; @InjectMocks private OrderBatchProcessor processor; @Test public void testOrderProcessing() { // Setup JobContext context = new JobContext(); context.setShardingIndex(0); context.setShardingTotal(3); List mockOrders = Arrays.asList( new Order(1L, "PENDING"), new Order(2L, "PENDING") ); when(orderService.getForShard(0, 3, any())).thenReturn(mockOrders); // Execute processor.processOrders(context); // Verify verify(orderService, times(2)).fulfill(any()); } } ``` -------------------------------- ### RPC Protocol Configuration Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/quick-reference.md Configuration settings for RPC communication, including message size and keep-alive parameters. ```yaml snail-job: rpcType: GRPC # GRPC (recommended) or HTTP clientRpc: maxInboundMessageSize: 10485760 # 10 MB keepAliveTime: 30s keepAliveTimeout: 10s serverRpc: maxInboundMessageSize: 10485760 keepAliveTime: 2h keepAliveTimeout: 20s ``` -------------------------------- ### Implement and Register RetryCompleteCallback Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/api-reference-core-interfaces.md A concrete implementation of the callback to handle success or failure states, followed by registration via the @Retryable annotation. ```java public class OrderRetryCallback implements RetryCompleteCallback { @Autowired private NotificationService notificationService; @Autowired private OrderService orderService; @Override public void retryComplete(RetryContext context) { String orderId = context.getBizNo(); if (context.isSuccess()) { // Retry succeeded notificationService.sendSuccess(orderId); orderService.markAsProcessed(orderId); } else { // Max retries exceeded notificationService.sendFailure(orderId, context.getLastError()); orderService.markAsFailedPermanent(orderId); // Alert operations team if (context.getAttemptCount() >= 3) { alertOps("Order " + orderId + " failed after " + context.getAttemptCount() + " retries"); } } } } // Usage: @Retryable( scene = "order_processing", retryCompleteCallback = OrderRetryCallback.class, localTimes = 2 ) public void processOrder(String orderId) { orderService.fulfill(orderId); } ``` -------------------------------- ### Implement Idempotent Retry with Business Key Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/advanced-patterns.md Uses a custom IdempotentIdGenerate implementation to ensure operations are not duplicated, keyed by a unique business identifier. ```java public class OrderPaymentIdempotentId implements IdempotentIdGenerate { @Override public String generate(Object... args) { Order order = (Order) args[0]; // Use order ID so same order isn't charged twice return "payment_order_" + order.getId(); } } @Retryable( scene = "order_payment", idempotentId = OrderPaymentIdempotentId.class, bizNo = "#order.orderId" // SpEL: order ID for UI filtering ) public void chargeOrder(Order order) { paymentGateway.charge(order); } ``` -------------------------------- ### Define SnailJobProperties Java Class Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/types.md The main configuration class for SnailJob client settings, annotated with @ConfigurationProperties. ```java @Configuration @ConfigurationProperties(prefix = "snail-job") @Getter @Setter public class SnailJobProperties { private String namespace; private String group; private String token; private String host; private Integer port = 17889; private RpcTypeEnum rpcType = RpcTypeEnum.GRPC; private Map labels = new HashMap<>(); private LogSlidingWindowConfig logSlidingWindow = new LogSlidingWindowConfig(); private ServerConfig server = new ServerConfig(); private HttpResponse httpResponse; private Retry retry = new Retry(); private SnailJobMailProperties mail = new SnailJobMailProperties(); private ForyProperties fory = new ForyProperties(); private SnailOpenApiConfig openapi = new SnailOpenApiConfig(); private String workspace; private RpcClientProperties clientRpc = new RpcClientProperties(); private RpcServerProperties serverRpc = new RpcServerProperties(); } ``` -------------------------------- ### Execute Parallel Tasks in Java Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/advanced-patterns.md Leverage CompletableFuture and a custom TaskExecutor to run independent tasks concurrently. Always handle exceptions within the async block to prevent silent failures. ```java @Component public class ParallelJobHandler { @Autowired private TaskExecutor executor; @JobExecutor(name = "parallelJob") public void executeParallel(JobContext context) { List tasks = getTasks(context); List> futures = new ArrayList<>(); for (Task task : tasks) { CompletableFuture future = CompletableFuture.runAsync( () -> { try { processTask(task); } catch (Exception e) { logger.error("Task {} failed", task.getId(), e); } }, executor ); futures.add(future); } // Wait for all to complete CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])) .exceptionally(ex -> { logger.error("Some parallel tasks failed", ex); return null; }) .join(); } } ``` -------------------------------- ### Thread Pool Configuration Source: https://github.com/aizuda/snail-job/blob/master/_autodocs/quick-reference.md Default thread pool settings for retry, client RPC, and server RPC components. ```yaml snail-job: retry: dispatcherThreadPool: corePoolSize: 32 # Core threads maximumPoolSize: 32 # Max threads keepAliveTime: 1 # Keep-alive seconds queueCapacity: 10000 # Queue size clientRpc: clientTp: corePoolSize: 16 maximumPoolSize: 16 queueCapacity: 10000 serverRpc: dispatcherTp: corePoolSize: 16 maximumPoolSize: 16 queueCapacity: 10000 ```