A distributed task scheduling framework core library for Java applications
—
Runtime context access and logging utilities for job execution. Provides thread-safe access to job parameters, logging, and result handling during job execution.
Static helper methods for accessing job execution context, logging, and handling job results. All methods are thread-safe and work within job execution threads.
/**
* Static utility class for job execution context and logging
* All methods are thread-safe and work within job execution context
*/
public class XxlJobHelper {
// Context access methods
/**
* Get current job ID
* @return Current job's unique identifier
*/
public static long getJobId();
/**
* Get job execution parameters passed from admin trigger
* @return Parameter string passed to job execution
*/
public static String getJobParam();
/**
* Get current job log file name
* @return Log file name for current job execution
*/
public static String getJobLogFileName();
/**
* Get shard index for distributed job execution
* @return Current shard index (0-based)
*/
public static int getShardIndex();
/**
* Get total number of shards for distributed job execution
* @return Total number of shards
*/
public static int getShardTotal();
// Logging methods
/**
* Log message with pattern formatting (similar to SLF4J)
* @param appendLogPattern - Log message pattern with {} placeholders
* @param appendLogArguments - Arguments to substitute in pattern
* @return true if log was written successfully
*/
public static boolean log(String appendLogPattern, Object... appendLogArguments);
/**
* Log exception with stack trace
* @param e - Exception to log
* @return true if log was written successfully
*/
public static boolean log(Throwable e);
// Result handling methods
/**
* Mark job execution as successful
* @return true if result was set successfully
*/
public static boolean handleSuccess();
/**
* Mark job execution as successful with custom message
* @param handleMsg - Success message
* @return true if result was set successfully
*/
public static boolean handleSuccess(String handleMsg);
/**
* Mark job execution as failed
* @return true if result was set successfully
*/
public static boolean handleFail();
/**
* Mark job execution as failed with error message
* @param handleMsg - Failure message
* @return true if result was set successfully
*/
public static boolean handleFail(String handleMsg);
/**
* Mark job execution as timed out
* @return true if result was set successfully
*/
public static boolean handleTimeout();
/**
* Mark job execution as timed out with custom message
* @param handleMsg - Timeout message
* @return true if result was set successfully
*/
public static boolean handleTimeout(String handleMsg);
/**
* Set custom result code and message
* @param handleCode - Custom result code (200=success, 500=fail, 502=timeout)
* @param handleMsg - Result message
* @return true if result was set successfully
*/
public static boolean handleResult(int handleCode, String handleMsg);
}Usage Examples:
import com.xxl.job.core.handler.annotation.XxlJob;
import com.xxl.job.core.context.XxlJobHelper;
@Component
public class ContextExampleJobHandler {
@XxlJob("contextExample")
public void contextExampleHandler() throws Exception {
// Access job context
long jobId = XxlJobHelper.getJobId();
String param = XxlJobHelper.getJobParam();
XxlJobHelper.log("Job {} started with param: {}", jobId, param);
try {
// Job logic here
processData(param);
// Log success
XxlJobHelper.log("Data processed successfully");
XxlJobHelper.handleSuccess("Processed " + dataCount + " records");
} catch (Exception e) {
XxlJobHelper.log("Job failed with exception: {}", e.getMessage());
XxlJobHelper.log(e); // Log full stack trace
XxlJobHelper.handleFail("Processing failed: " + e.getMessage());
}
}
@XxlJob("shardedExample")
public void shardedExampleHandler() throws Exception {
// Get sharding information
int shardIndex = XxlJobHelper.getShardIndex();
int shardTotal = XxlJobHelper.getShardTotal();
XxlJobHelper.log("Processing shard {} of {} shards", shardIndex, shardTotal);
// Process only data for this shard
List<Data> allData = getAllData();
List<Data> shardData = new ArrayList<>();
for (int i = shardIndex; i < allData.size(); i += shardTotal) {
shardData.add(allData.get(i));
}
XxlJobHelper.log("Shard {} will process {} items", shardIndex, shardData.size());
// Process shard data
for (Data item : shardData) {
processItem(item);
}
XxlJobHelper.handleSuccess("Shard " + shardIndex + " processed " + shardData.size() + " items");
}
@XxlJob("progressExample")
public void progressExampleHandler() throws Exception {
List<Task> tasks = getTasks();
int totalTasks = tasks.size();
int completed = 0;
XxlJobHelper.log("Starting processing of {} tasks", totalTasks);
for (Task task : tasks) {
try {
processTask(task);
completed++;
// Log progress every 10%
if (completed % Math.max(1, totalTasks / 10) == 0) {
int percentage = (completed * 100) / totalTasks;
XxlJobHelper.log("Progress: {}/{}% ({}/{})",
percentage,completed, totalTasks);
}
} catch (Exception e) {
XxlJobHelper.log("Task {} failed: {}", task.getId(), e.getMessage());
// Continue processing other tasks
}
}
XxlJobHelper.handleSuccess("Completed " + completed + "/" + totalTasks + " tasks");
}
}Job execution context holder that maintains job state and execution information in thread-local storage.
/**
* Job execution context holder using thread-local storage
* Provides access to current job execution state and parameters
*/
public class XxlJobContext {
// Result code constants
/**
* Success result code
*/
public static final int HANDLE_CODE_SUCCESS = 200;
/**
* Failure result code
*/
public static final int HANDLE_CODE_FAIL = 500;
/**
* Timeout result code
*/
public static final int HANDLE_CODE_TIMEOUT = 502;
// Context management
/**
* Set job context for current thread
* @param xxlJobContext - Context instance to set
*/
public static void setXxlJobContext(XxlJobContext xxlJobContext);
/**
* Get job context for current thread
* @return Current thread's job context or null if not in job execution
*/
public static XxlJobContext getXxlJobContext();
// Context data accessors
/**
* Get current job ID
* @return Job identifier
*/
public long getJobId();
/**
* Get job execution parameters
* @return Parameter string
*/
public String getJobParam();
/**
* Get job log file name
* @return Log file name for current execution
*/
public String getJobLogFileName();
/**
* Get shard index for distributed execution
* @return Current shard index
*/
public int getShardIndex();
/**
* Get total shard count for distributed execution
* @return Total number of shards
*/
public int getShardTotal();
/**
* Get job execution handle code
* @return Current result code (200=success, 500=fail, 502=timeout)
*/
public int getHandleCode();
/**
* Get job execution handle message
* @return Current result message
*/
public String getHandleMsg();
}@XxlJob("parameterProcessor")
public void parameterProcessorHandler() throws Exception {
String param = XxlJobHelper.getJobParam();
if (param == null || param.trim().isEmpty()) {
XxlJobHelper.handleFail("Job parameter is required");
return;
}
try {
// Parse JSON parameters
ObjectMapper mapper = new ObjectMapper();
JobParameters params = mapper.readValue(param, JobParameters.class);
XxlJobHelper.log("Processing with parameters: startDate={}, endDate={}, mode={}",
params.getStartDate(), params.getEndDate(), params.getMode());
// Validate parameters
if (params.getStartDate().isAfter(params.getEndDate())) {
XxlJobHelper.handleFail("Start date must be before end date");
return;
}
// Process with parameters
processDateRange(params.getStartDate(), params.getEndDate(), params.getMode());
XxlJobHelper.handleSuccess("Processed date range successfully");
} catch (JsonProcessingException e) {
XxlJobHelper.log("Invalid JSON parameter: {}", e.getMessage());
XxlJobHelper.handleFail("Invalid parameter format: " + e.getMessage());
}
}@XxlJob("distributedProcessor")
public void distributedProcessorHandler() throws Exception {
int shardIndex = XxlJobHelper.getShardIndex();
int shardTotal = XxlJobHelper.getShardTotal();
XxlJobHelper.log("Shard {}/{} starting processing", shardIndex + 1, shardTotal);
// Get data for this shard
List<Long> allIds = getAllRecordIds();
List<Long> shardIds = new ArrayList<>();
// Distribute IDs across shards
for (int i = shardIndex; i < allIds.size(); i += shardTotal) {
shardIds.add(allIds.get(i));
}
XxlJobHelper.log("Shard {} will process {} records", shardIndex, shardIds.size());
int processed = 0;
int failed = 0;
for (Long id : shardIds) {
try {
processRecord(id);
processed++;
// Log progress periodically
if (processed % 100 == 0) {
XxlJobHelper.log("Shard {} processed {} records", shardIndex, processed);
}
} catch (Exception e) {
failed++;
XxlJobHelper.log("Failed to process record {}: {}", id, e.getMessage());
}
}
String result = String.format("Shard %d completed: %d processed, %d failed",
shardIndex, processed, failed);
if (failed == 0) {
XxlJobHelper.handleSuccess(result);
} else {
XxlJobHelper.handleFail(result);
}
}@XxlJob("longRunningJob")
public void longRunningJobHandler() throws Exception {
String param = XxlJobHelper.getJobParam();
int batchSize = param != null ? Integer.parseInt(param) : 1000;
XxlJobHelper.log("Starting long-running job with batch size: {}", batchSize);
long totalRecords = getTotalRecordCount();
long processed = 0;
long startTime = System.currentTimeMillis();
XxlJobHelper.log("Total records to process: {}", totalRecords);
try {
while (processed < totalRecords) {
long remaining = Math.min(batchSize, totalRecords - processed);
XxlJobHelper.log("Processing batch: {} records (offset: {})", remaining, processed);
// Process batch
List<Record> batch = getRecordBatch(processed, (int) remaining);
for (Record record : batch) {
processRecord(record);
}
processed += remaining;
// Log progress
double percentage = (processed * 100.0) / totalRecords;
long elapsed = System.currentTimeMillis() - startTime;
long estimatedTotal = (long) (elapsed / (percentage / 100.0));
long remaining = estimatedTotal - elapsed;
XxlJobHelper.log("Progress: {}/{} ({:.1f}%) - ETA: {} seconds",
processed, totalRecords, percentage, remaining / 1000);
}
long totalTime = System.currentTimeMillis() - startTime;
XxlJobHelper.handleSuccess("Processed " + processed + " records in " + totalTime + "ms");
} catch (Exception e) {
XxlJobHelper.log("Job failed after processing {} records: {}", processed, e.getMessage());
XxlJobHelper.log(e);
XxlJobHelper.handleFail("Failed after processing " + processed + " records");
}
}@XxlJob("resultHandler")
public void resultHandlerHandler() throws Exception {
try {
String result = performBusinessLogic();
// Handle different result scenarios
if (result.equals("PARTIAL_SUCCESS")) {
XxlJobHelper.handleResult(200, "Completed with warnings: " + result);
} else if (result.equals("NO_DATA")) {
XxlJobHelper.handleResult(200, "No data to process");
} else if (result.equals("BUSINESS_ERROR")) {
XxlJobHelper.handleResult(500, "Business logic error: " + result);
} else {
XxlJobHelper.handleSuccess("Processing completed: " + result);
}
} catch (TimeoutException e) {
XxlJobHelper.handleTimeout("Operation timed out after " + e.getTimeout() + "ms");
} catch (BusinessException e) {
XxlJobHelper.handleFail("Business error: " + e.getMessage());
} catch (Exception e) {
XxlJobHelper.log(e);
XxlJobHelper.handleFail("Unexpected error: " + e.getClass().getSimpleName());
}
}@XxlJob("structuredLogging")
public void structuredLoggingHandler() throws Exception {
long jobId = XxlJobHelper.getJobId();
String param = XxlJobHelper.getJobParam();
// Use structured log format
XxlJobHelper.log("[JOB_START] jobId={}, param={}, timestamp={}",
jobId, param, System.currentTimeMillis());
try {
// Business logic with structured logging
XxlJobHelper.log("[PROCESSING] action=data_fetch, status=started");
List<Data> data = fetchData();
XxlJobHelper.log("[PROCESSING] action=data_fetch, status=completed, count={}", data.size());
XxlJobHelper.log("[PROCESSING] action=data_transform, status=started");
List<Data> transformed = transformData(data);
XxlJobHelper.log("[PROCESSING] action=data_transform, status=completed, count={}", transformed.size());
XxlJobHelper.log("[JOB_END] status=success, processed={}", transformed.size());
XxlJobHelper.handleSuccess("Processed " + transformed.size() + " records");
} catch (Exception e) {
XxlJobHelper.log("[JOB_END] status=error, error={}", e.getMessage());
XxlJobHelper.log(e);
XxlJobHelper.handleFail(e.getMessage());
}
}Install with Tessl CLI
npx tessl i tessl/maven-com-xuxueli--xxl-job-core