Exploring PowerJob: A Lightweight Distributed Task Scheduler for Java
This article introduces PowerJob, a young yet powerful distributed task scheduling framework, covering its selection reasons, core concepts, high‑availability setup, workflow types, scheduling modes, deployment steps, and detailed code examples for single, broadcast, map, and MapReduce jobs.
1. Why Choose PowerJob
PowerJob is a young, lightweight distributed task framework that requires only MySQL, has simple code, comprehensive features, and has quickly gained popularity (1.8k stars) with adoption by large companies.
1.1 Product Comparison
Official documentation provides a comparison chart (see image).
1.2 Features
Simple, easy‑to‑understand code; customizable (e.g., integrated with custom service discovery).
All common scheduling features are supported.
Very lightweight; no external services like Zookeeper needed.
1.3 Maturity
Product launched for 3 months, already has 1.8k stars and is used by many large enterprises (see images).
2. PowerJob Workflow
2.1 Basic Concepts
An app is a project, a worker is a node of the app, a job is a task (simple or MapReduce), and a server is the PowerJob node that listens and dispatches tasks.
2.2 App & Server Binding
Workers register their server addresses; upon startup they send heartbeats and perform discovery. High‑availability is achieved by deploying multiple server nodes (master + slaves).
2.3 High Availability
If a server fails, PowerJob uses a discovery mechanism to failover to a backup node.
2.4 Server Scheduling
The server polls and dispatches jobs to workers.
2.5 Deployment Steps
Deploy PowerJob server.
Develop job classes in your app project.
Register the app in the PowerJob client.
Start the app; workers bind to the server.
Configure jobs (cron, concurrency, etc.) via the client.
After these steps, jobs are scheduled by the server.
3. Task Types & Validation
3.1 Defining a PowerJob Task
Implement PowerJob‑provided interfaces; the framework obtains instances from Spring or via reflection.
3.1 Single‑Machine Task
@Slf4j
@Component
public class StandaloneProcessor implements BasicProcessor {
// core logic
@Override
public ProcessResult process(TaskContext context) {
log.info("Simple scheduled task triggered! Params: {}", context.getJobParams());
return new ProcessResult(true, context + ": " + true);
}
}After publishing, configure the job in the PowerJob UI and run it.
3.2 Broadcast Task
@Slf4j
@Component
public class BroadcastProcessorDemo extends BroadcastProcessor {
@Override
public ProcessResult preProcess(TaskContext context) throws Exception {
log.info("Broadcast pre‑process, params: {}", context.getJobParams());
return new ProcessResult(true);
}
@Override
public ProcessResult process(TaskContext taskContext) throws Exception {
log.info("Broadcast core logic, params: {}", taskContext.getJobParams());
return new ProcessResult(true);
}
@Override
public ProcessResult postProcess(TaskContext context, List<TaskResult> taskResults) throws Exception {
log.info("Broadcast post‑process, results: {}", JSONObject.toJSONString(taskResults));
return new ProcessResult(true, "success");
}
}3.3 Map Task (Large Task Splitting)
public class MapProcessorDemo extends MapProcessor {
private static final int batchSize = 100;
private static final int batchNum = 2;
@Override
public ProcessResult process(TaskContext context) throws Exception {
if (isRootTask()) {
List<SubTask> subTasks = Lists.newLinkedList();
for (int j = 0; j < batchNum; j++) {
SubTask subTask = new SubTask();
subTask.siteId = j;
subTask.itemIds = Lists.newLinkedList();
for (int i = 0; i < batchSize; i++) {
subTask.itemIds.add(i);
}
subTasks.add(subTask);
}
return map(subTasks, "MAP_TEST_TASK");
} else {
SubTask subTask = (SubTask) context.getSubTask();
log.info("Subtask received: {}", JSON.toJSONString(subTask));
return new ProcessResult(true, "RESULT:true");
}
}
@Getter @NoArgsConstructor @AllArgsConstructor
private static class SubTask {
private Integer siteId;
private List<Integer> itemIds;
}
}3.4 MapReduce Task
public class MapReduceProcessorDemo extends MapReduceProcessor {
private static final int batchSize = 100;
private static final int batchNum = 2;
@Override
public ProcessResult process(TaskContext context) {
if (isRootTask()) {
List<SubTask> subTasks = Lists.newLinkedList();
for (int j = 0; j < batchNum; j++) {
SubTask subTask = new SubTask();
subTask.siteId = j;
subTask.itemIds = Lists.newLinkedList();
for (int i = 0; i < batchSize; i++) {
subTask.itemIds.add(i);
}
subTasks.add(subTask);
}
return map(subTasks, "MAP_TEST_TASK");
} else {
SubTask subTask = (SubTask) context.getSubTask();
log.info("Subtask received: {}", JSON.toJSONString(subTask));
return new ProcessResult(true, "RESULT:true");
}
}
@Override
public ProcessResult reduce(TaskContext context, List<TaskResult> taskResults) {
log.info("Reduce triggered. Context: {}, Results: {}", JSONObject.toJSONString(context), JSONObject.toJSONString(taskResults));
return new ProcessResult(true, "RESULT:true");
}
@Getter @NoArgsConstructor @AllArgsConstructor
private static class SubTask {
private Integer siteId;
private List<Integer> itemIds;
}
}3.5 Workflow
Define a sequence like TaskA → TaskB → TaskC in the UI to create a workflow; the workflow has its own trigger, ignoring CRON settings.
4. Scheduling Types & Validation
4.1 CRON Expressions
Supports standard CRON (no second‑level granularity). For sub‑minute tasks use fixed‑rate or fixed‑delay.
4.2 Fixed Rate
Executes tasks at a constant interval regardless of execution time.
4.3 Fixed Delay
Executes the next task only after the previous one finishes, then waits the specified delay.
5. Miscellaneous
5.1 Task Form Details
Refer to the official documentation for field explanations.
5.2 Workflow Configuration
See the official guide; note some usability quirks.
Finally, the author asks readers to like, follow, share, and support the content.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Code Ape Tech Column
Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
