Anthills is a lightweight distributed database-backed Job and Worker library for Java. It helps you run Scheduled Jobs and background workers safely across multiple nodes, without leader election, message queues, or extra infrastructure.
Use your database as the source of truth.
Let nodes come and go freely.
Distributed coordination is hard β but most applications already have a database. Anthills lets you build reliable distributed systems using primitives you already trust:
- transactions
- timestamps
- row-level locks
No Kafka. No ZooKeeper. No Redis locks. No leader election.
Just leases + workers.
- β Distributed-safe execution
- π Lease-based work claiming
- π Automatic retries with limits
- π§ DB as the source of truth
- π« No duplicate execution
- πͺΆ No heavyweight dependencies (no Kafka / no ORM required)
- β
Run scheduled jobs on only one node
- Even if your app runs on 10 servers.
- β
Process background work across many nodes
- With retries, backoff, and crash recovery.
- β
Handle long-running tasks safely
- Leases are automatically renewed while work runs.
- β
Survive crashes and restarts
- Expired leases allow other nodes to take over.
Anthills has two main primitives:
βRun this job periodically, but only on one node.β
Use this for:
- cleanup jobs
- reconciliation
- scheduled maintenance
- aggregation tasks
scheduler.schedule("hello-world-job", Schedule.Cron.parse("* * * * *"), () -> System.out.println("Hello world"));Deploy this on every node β Anthills ensures only one executes it.
βProcess background work across many nodes.β
Use this for:
- email / SMS sending
- async workflows
- retries and compensation logic
- event-driven processing
processor.registerHandler("notification", SendEmail.class, req -> sendEmail(req.payload()));
WorkRequest<SendEmail> request = workClient.submit(new SendEmail("hello@example.com", "Hello", "Hello from Anthills!"));Work is:
- persisted
- leased
- retried with backoff
- safely redistributed on failure
A WorkRequest represents a single unit of work stored in the database.
public record WorkRequest<T>(
String id,
String workType,
T payload,
int payloadVersion,
String codec,
Status status,
int maxRetries,
int attemptCount,
String ownerId,
Instant leaseUntil,
String failureReason,
Instant createdTs,
Instant updatedTs,
Instant startedTs,
Instant completedTs
) {}New
β
InProgress
β
Succeeded | Failed | Cancelled
ββββββββββββ
β Database β β source of truth
ββββββ¬ββββββ
β
ββββββΌβββββββββββ
β Leases β
β (time-bound) β
ββββββ¬βββββββββββ
β
ββββββΌβββββββββββ
β Workers β
β (any node) β
βββββββββββββββββ- Work is claimed with a lease
- Leases expire automatically
- Active work renews its lease
- Crashed nodes lose ownership
- Other nodes recover the work
No global state. No coordination service. No single point of failure.
anthills
βββ anthills-api # Public interfaces & models
βββ anthills-core # Core execution logic
βββ anthills-jdbc # JDBC-based implementation
βββ anthills-examples # Runnable examples<!-- Contains API and Core implementation -->
<dependency>
<groupId>org.anthills</groupId>
<artifactId>anthills-core</artifactId>
<version>${anthills.version}</version>
</dependency>
<!-- JDBC Implementation of WorkStore -->
<dependency>
<groupId>org.anthills</groupId>
<artifactId>anthills-jdbc</artifactId>
<version>${anthills.version}</version>
</dependency>WorkStore store = JdbcWorkStore.create(dataSource);LeasedScheduler scheduler = Schedulers.create(SchedulerConfig.defaults(), store);
scheduler.schedule("hello-world", FixedRate.every(Duration.ofSeconds(5)), () -> System.out.println("Hello from Anthills"));
scheduler.start();Run this on multiple nodes β it still executes once per interval.
WorkRequestProcessor processor = WorkRequestProcessors.create("notification", store, JsonPayloadCodec.defaultInstance(), ProcessorConfig.defaults());
processor.registerHandler("notification", SendEmail.class, req -> sendEmail(req.payload()));
processor.start();Submit work from anywhere:
WorkClient workClient = WorkClients.create(workStore);
workClient.submit("notification", new SendEmail("user@example.com", "Hi", "Hello!"));- a distributed coordination library
- database-backed and transaction-safe
- simple to reason about
- crash-resilient by design
- framework-agnostic
- a message queue
- a stream processor
- a workflow engine
- a replacement for Kafka
- a leader-election framework
Anthills is about execution guarantees, not messaging semantics.
Because they are:
- already available
- strongly consistent
- observable
- debuggable
You can:
- inspect tables
- see who owns what
- manually intervene if needed
- Operational transparency is a feature.
See anthills-examples for:
- HelloWorld scheduled jobs
- Fixed-rate vs cron scheduling
- Distributed background workers
- Retry and backoff behavior
Anthills is built on a few strong principles:
- Leases over locks
- Failure is normal
- Recovery over prevention
- Simple beats clever
- Infrastructure should be boring
Anthills is a great fit if you:
- already use a relational database
- run multiple instances of your app
- need reliable background execution
- want minimal infrastructure
- value debuggability
Contributions are welcome!
- Areas of interest:
- alternative persistence backends
- metrics & observability
- performance tuning
- documentation & examples
Please open an issue or PR to discuss.
License
Apache License 2.0
ππππππππππππππππππππππ
