XXL-JOB: a central scheduler with self-registering executors
A distributed task scheduling framework.(分布式任务调度平台XXL-JOB)
At a glance
- What is it?
- XXL-JOB splits scheduling into an admin centre and Java executors that register themselves over HTTP. The design is easy to reason about and easy to operate, but the admin database is a single point of truth and the GPL-3.0 licence shapes where you can put the code.
- Who is it for?
- Adopt XXL-JOB if you have Java services that need cron-style scheduling with a web console, per-executor permissions, and sharding across a cluster, and if GPL-3.0 fits how you ship code. Do not adopt it if you need sub-second timers, a scheduler that keeps firing when the admin database is unavailable, or a permissive licence for a closed product.
- Can I use it commercially?
- Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository last received commits 56 days ago.
- What is it written in?
- Mainly Java, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The problem XXL-JOB solves: cron jobs that outgrow one machine
A single application with @Scheduled annotations works until the application runs on three replicas. Then the same job fires three times, or fires on whichever instance the load balancer happened to pick. XXL-JOB exists to move that decision out of the application and into a separate scheduling service. The README states the core design goal plainly: develop quickly, learn simply, stay lightweight, and be easy to expand. The target user is a Java team that already runs Spring services and wants a console where operations staff can see job history, change a cron expression, pause a job, or kill a running execution without a redeploy. The feature list is aimed at that operational surface rather than at high-frequency event processing: web CRUD for tasks, start and stop, terminate a running task, email alerts on failure, and a running report view. If your scheduling need is a few dozen business jobs on a handful of services, that is the shape this project was built for.
Admin centre, executor registry, and what actually crosses the network
The architecture has two roles. The scheduling centre (xxl-job-admin) owns the cron expressions, the job definitions, the trigger log and the web UI. Executors are the processes that contain the job code. According to the feature list, executors register themselves periodically, and the admin discovers registered executors automatically; manual entry of an executor address is also supported. That registration is what makes scaling simple: bring up a new executor instance, and the next scheduling round sees it. When a trigger fires, the admin selects an executor according to the routing strategy and sends a scheduling request over HTTP. The routing strategies listed include first, last, round-robin, random, consistent hash, least frequently used, least recently used, failover and busy transfer. Consistency across a cluster of admins is handled by a database lock, so a single trigger produces a single execution. The communication between admin and executor is encrypted, per feature 26. Two details matter for capacity planning. First, scheduling is asynchronous end to end (async dispatch, async run, async callback), which the README frames as traffic shaping for dense schedules. Second, the scheduling thread pool is split, and slow tasks are demoted into a separate Slow pool so they cannot exhaust the dispatch threads. That isolation is the most interesting design decision in the list, because it turns a class of production incident into a queueing problem.
Getting it running: admin, database, and the executor side
The project publishes to Maven Central under the coordinate com.xuxueli:xxl-job-core, and an official Docker image is pushed to Docker Hub as xuxueli/xxl-job-admin. The typical local sequence is: create the admin database from the SQL script shipped in the repository, edit the datasource settings in the admin configuration, start the admin application, then add the xxl-job-core dependency to your business service and configure the executor. The README also points at a Chinese documentation page and an English documentation page at xuxueli.com for the full configuration reference, so treat those pages as the source of truth for property names and version-specific behaviour rather than any snippet in a third-party article. On the executor side, jobs are written either as bean handlers (the README names CommandJobHandler as the built-in handler for command-line tasks) or in GLUE mode, where you write the job logic in a web IDE and it is compiled and published without a deploy. GLUE keeps 30 historical versions for rollback. Script jobs in GLUE mode cover Shell, Python, NodeJS, PHP and PowerShell. The admin UI supports Chinese and English, defaulting to Chinese.
Where the design pushes back: blocking, missed triggers, and the database lock
Three policies deserve attention before you schedule anything important. The blocking strategy decides what happens when a trigger arrives while the previous execution is still running. The default is single-machine serial execution; the alternatives are discarding the later trigger or overwriting the earlier one. The scheduling expiry policy decides what happens when the admin misses a trigger time, with options including ignoring it or compensating with an immediate trigger. The failure retry count is configurable, and sharded jobs retry at shard granularity. None of these defaults is wrong, but each one is a decision about your business that the framework will make silently if you do not set it. The larger limitation is structural: the README describes the admin as a centralised design, and consistency is enforced through a database lock. That means the admin's database is the single point of truth for what should run and what has run. A cluster of admins gives you high availability of the scheduling process, but it does not remove the database. If you need scheduling to continue while that database is unreachable, this is the wrong tool. The same centralisation makes the admin a natural bottleneck to watch as job counts grow, since every trigger decision passes through it.
Sharding, GLUE, and the AI handlers in 3.x
The sharding broadcast routing strategy is the feature that most changes how you write code. With it, one trigger broadcasts to every executor in the cluster, and each executor receives a shard index and total, so you can partition a large data operation across machines. Adding executor instances increases the shard count dynamically. This is genuinely different from running the same job on one elected instance: the work is divided, not duplicated. GLUE is the other feature with real workflow consequences, because it moves job code out of your repository and into the admin's database with a web IDE and 30 versions of history. That is convenient for operations teams and awkward for teams whose release process requires code review and version control. The 3.x line also adds an AI executor with built-in AI task handlers, described as integrated with spring-ai, ollama, openclaw and dify. Treat that as a convenience wrapper over HTTP calls to those services, not as a scheduling capability; the scheduling semantics are unchanged.
Quartz, Kubernetes CronJobs, and what changes if you switch
The closest alternative in the same language ecosystem is Quartz, and the difference is architectural rather than cosmetic. Quartz is a library you embed in your application; each application instance participates in scheduling and coordinates with the others through a shared JDBC job store and locks. XXL-JOB is a service you deploy separately, with its own UI, its own user and permission model, and executors that only execute what they are told. With Quartz, job definitions live in your application's code and schema. With XXL-JOB, they live in the admin database and are edited through a web page. That makes XXL-JOB better when non-developers need to pause a job at 2am, and worse when you want job configuration to travel through the same review and deployment pipeline as the rest of your code. If your workloads already run on Kubernetes, CronJob is a third option with no extra service to operate, but it has no cross-cluster job registry, no routing strategies, and no built-in failure alerting, so the comparison usually ends at how much operational surface you want to own.
Licence, maintenance, and what upgrading actually costs
XXL-JOB is GPL-3.0. That is a copyleft licence, and it is the single most consequential fact for commercial adopters. Linking xxl-job-core into a proprietary service is a question for your own legal counsel, not for a review article; the point here is that the licence is not permissive in the way Apache-2.0 or MIT are, and teams that assume otherwise discover it late. On maintenance, the release cadence visible in the repository is active: 3.4.0 in April 2026, 3.4.1 in June 2026, 3.4.2 later the same month, with the last push to master in July 2026. Upgrades are not free, however. The admin is a stateful service with a database schema, so a version bump means reading the release notes for schema changes, applying them to the admin database, and restarting the admin. Executors carry the xxl-job-core dependency and need a coordinated upgrade if the admin-to-executor protocol changes. The README's graceful shutdown behaviour, where the admin waits for the time wheel to drain and executors stop accepting new tasks while running ones finish, exists precisely to make that restart less disruptive, and it is worth testing in a staging environment before you rely on it during a production upgrade.
Editorial conclusion
Adopt XXL-JOB if you have Java services that need cron-style scheduling with a web console, per-executor permissions, and sharding across a cluster, and if GPL-3.0 fits how you ship code. Do not adopt it if you need sub-second timers, a scheduler that keeps firing when the admin database is unavailable, or a permissive licence for a closed product. Before committing, verify three things in your own environment: that your MySQL version is supported by the admin schema, that the executor registration interval and the admin's scheduling thread pools behave under your expected job count, and that losing the admin centre leaves your critical jobs in a state you can accept.
Community notes