module

JoobQ

Constants

EXIT_ABANDONED = 3
EXIT_CLEAN = 0

Exit status of forge after a clean shutdown, and after one that had to abandon jobs at the deadline.

JSONLogFormatter = ::Log::Formatter.new do |entry, io| JSON.build(io) do |json| json.object do json.field("timestamp", entry.timestamp.to_rfc3339) json.field("severity", entry.severity.to_s.downcase) json.field("source", entry.source) json.field("message", entry.message) json.field("pid", Process.pid) json.field("data", entry.data) json.field("context", entry.context) if error = entry.exception json.field("exception") do json.object do json.field("class", error.class.name) json.field("message", error.message) end end end end end end

Opt-in NDJSON for Log::IOBackend. Structured job/worker/queue fields emitted by the library live in data; application correlation fields live in context. Applications must redact secrets before logging them, including exception messages.

SHUTDOWN_GRACE = 200.milliseconds

The least a step that must run gets, whatever is left of the budget.

SHUTDOWN_RESERVE = 1.second

Time kept back at the end of the budget (at most half of it) for putting abandoned jobs back and flushing the latency counters, so a stuck job that used up the wait does not leave those steps with nothing.

SHUTDOWN_TIMEOUT = 15.seconds

How long JoobQ.shutdown waits, all steps together, before it gives up and returns.

VERSION = {{ ((read_file("/tmp/tmp.ffimNB/src/src/../shard.yml")).lines.find(&.starts_with?("version:")).split(":"))[1].strip }}

Class methods

[](name : String)
Source
abandoned_jobs

How many jobs the shutdown had to give up on (returned to their queues) because they were still running at the deadline. Zero after a clean shutdown.

Source
add(job)
Source
config
Source
configure
Source
configured_store?

The configured store, or nil while no configuration exists. Never loads the configuration, so it is safe to call from code that runs while the configuration itself is being built.

Source
enqueue(queue_name : String, json : String) : String

Enqueues a serialized job onto a registered queue and returns its job id. Unlike Queue#add, which logs a payload that does not fit the queue's job type and moves on, this raises: UnknownQueue for a queue that is not registered, and the JSON error (JSON::ParseException, JSON::SerializableError) for a bad payload.

Source
error_monitor
Source
find_config_file
Source
forge(trap_signals : Bool = trap_signals_default?, shutdown_timeout : Time::Span = SHUTDOWN_TIMEOUT)

Starts the schedulers, the reaper, the queues and (when enabled) the REST API, then blocks.

With trap_signals (the default), forge never returns: SIGTERM, SIGINT and SIGHUP (Process.on_terminate traps all three) run JoobQ.shutdown with shutdown_timeout and then exit the process, with status 0, or 3 when jobs were still running at the deadline and had to be returned to their queues. A second signal more than a second after the first exits at once with status 1. Code after the forge call does not run.

With trap_signals: false (also the default when the environment variable JOOBQ_TRAP_SIGNALS is 0, false or no) the application owns the signals: it calls JoobQ.shutdown itself, and forge returns once that has finished.

Source
initialize_config

Initialize configuration with auto-discovery

Source
initialize_config_with(loading_method : Symbol, *args, **kwargs) : Nil

Initialize configuration with specific loading method

Source
initialize_config_with(loading_method : Symbol, *args, **kwargs, &) : Nil

Initialize configuration with hybrid loading method (requires block)

Source
load_auto
Source
load_from_cli_args(args : Array(String)) : Configure
Source
load_from_file(path : String) : Configure
Source
load_from_string(yaml_content : String, source_path : String | Nil = nil) : Configure
Source
load_from_yaml(path : String | Nil = nil, env : String | Nil = nil) : Configure

Configuration loading methods

Source
load_from_yaml_sources(sources : Array(String)) : Configure
Source
load_hybrid(yaml_path : String | Nil = nil, &)
Source
load_with_env_overrides(base_path : String | Nil = nil, env : String | Nil = nil) : Configure
Source
queues
Source
reset
Source
reset_config

Reset configuration (useful for testing)

Source
scheduler
Source
set_config(config : Configure) : Nil

Set a custom configuration

Source
shut_down?

True once shutdown has begun.

Source
shutdown(timeout : Time::Span = SHUTDOWN_TIMEOUT) : Bool

Stops this process in order, within timeout in total:

  1. the REST API started by forge (no new requests)
  2. every scheduler of the configuration, the delayed-job scheduler and the expired-job reaper (no new work)
  3. the workers of every queue (they claim nothing more)
  4. the jobs claimed or running, waited for until timeout minus SHUTDOWN_RESERVE (at most half of timeout)
  5. the jobs still not finished then: each is put back at the head of its queue in one atomic step, so they run next in the order this process took them (RedisStore#requeue_many_from_processing; jobs still settling are put back a moment later, in front of them), jobs not yet started are never started, and abandoned_jobs counts them
  6. the latency counters (flushed to Redis)

What a job does after it was put back: its execution may well go on (a fiber cannot be killed) and finish its own side effects inside perform (a call to another system, a row written). What JoobQ itself does for it is switched off: it is not retried, dead-lettered, counted as processed or failed, announced, or removed from the processing list, so the requeued copy is the only one JoobQ schedules. Workers also claim nothing once the shutdown has begun.

Step 5 is the shutdown's own recovery: it does not rely on the start-up recovery of the next process (Queue#start and the reaper reclaim the processing lists of crashed or stopped processes, never a live one's). A job put back this way runs again from the start, possibly in another process while this one winds down: jobs must be safe to run twice, as they already must be after a crash. A job that crashes the process before step 5 (SIGKILL) is still left to the start-up recovery.

Safe to call from any fiber, any number of times: the first call does the work and returns true, later calls (also while the first is still running) wait for it and return false. After a shutdown the queues of this process cannot be started again.

Source
shutdown_finished?

True once shutdown has finished.

Source
store
Source
trap_signals_default?

False when the environment variable JOOBQ_TRAP_SIGNALS is 0, false or no.

Source
trap_termination(timeout : Time::Span) : Nil

SIGTERM, SIGINT and SIGHUP (Process.on_terminate covers all three): shut down, then exit with status 0, or 3 when jobs had to be abandoned at the deadline. A second signal more than a second after the first (an impatient operator; a duplicate sent by a process group or a wrapper arrives together with the first and is ignored) exits at once with status 1.

Source

Nested types