Skip to main content
The CronSchedulerAdapter trait defines the interface for distributed locking in III’s cron system. Cron adapters ensure that scheduled jobs run exactly once across multiple engine instances.

Trait Definition

Source: /workspace/source/src/modules/cron/structs.rs:26

Methods

try_acquire_lock

Attempts to acquire a distributed lock for a cron job execution. Parameters:
  • job_id - Unique identifier for the cron job
Returns:
  • true if the lock was successfully acquired
  • false if another instance already holds the lock
Behavior:
  • Must be atomic to prevent race conditions
  • Lock should have a TTL to prevent deadlocks if an instance crashes
  • Only one instance across the cluster should acquire the lock
  • Typical TTL: 30 seconds

release_lock

Releases the distributed lock for a cron job. Parameters:
  • job_id - Unique identifier for the cron job
Behavior:
  • Should only release locks owned by the current instance
  • Must be atomic to prevent releasing another instance’s lock
  • Safe to call even if lock is not held
  • Called automatically after job execution completes

Available Adapters

RedisCronAdapter

Redis-based distributed locking using atomic SET operations with TTL.
Features:
  • True distributed locking across multiple instances
  • Atomic lock acquisition using Redis SET NX PX
  • Automatic lock expiration after 30 seconds
  • Lua script for atomic lock release
  • Prevents duplicate job executions in clustered environments
Lock Mechanism:
Source: /workspace/source/src/modules/cron/adapters/redis_adapter.rs

KvCronAdapter

Process-local key-value based locking for single-instance deployments.
Features:
  • In-memory locking using built-in KV store
  • Zero external dependencies
  • Shared lock store across adapter instances in the same process
  • Suitable for development and single-instance deployments
Warning: This adapter uses process-local locks. In multi-instance deployments, cron jobs may run on every engine instance. Use RedisCronAdapter for distributed setups. Configuration:
  • lock_ttl_ms - Lock time-to-live in milliseconds (default: 30000)
  • lock_index - KV store index for locks (default: “cron_locks”)
Source: /workspace/source/src/modules/cron/adapters/kv_adapter.rs

How Cron Locking Works

  1. Scheduled Time Arrives: Each engine instance calculates the next execution time independently
  2. Lock Attempt: When the time arrives, all instances try to acquire the lock
  3. Single Execution: Only one instance succeeds in acquiring the lock
  4. Job Execution: The lock holder executes the cron job function
  5. Lock Release: After completion (success or failure), the lock is released
  6. Lock Expiration: If the instance crashes, the lock auto-expires after TTL

Example Implementation

Redis Implementation Details

The RedisCronAdapter uses Redis atomic operations to ensure distributed locking:

Lock Acquisition

Lock Release

Best Practices

Lock TTL

  • Set TTL longer than the maximum expected job execution time
  • Default 30 seconds works for most jobs
  • Consider job-specific TTLs for long-running tasks
  • TTL prevents deadlocks if an instance crashes

Error Handling

Instance Identification

  • Use UUIDs for instance IDs to ensure uniqueness
  • Store instance ID when acquiring locks
  • Verify ownership before releasing locks
  • Prevents accidentally releasing another instance’s lock