Enum Class JobDispatcher

java.lang.Object
java.lang.Enum<JobDispatcher>
ai.redouble.nucleo.harness.JobDispatcher
All Implemented Interfaces:
Serializable, Comparable<JobDispatcher>, Constable

public enum JobDispatcher extends Enum<JobDispatcher>
The runtime: one dispatcher per process, the entry point for every job submission and the one execution path every job takes. A submission passes the door (authority, parent, scope), is queued by its timeout (five seconds or less to the priority queue, longer to the FIFO queue, none at all when it declines queueing), and executes on a virtual thread: dependencies awaited, input guards, model resolution and pricing, admission of the whole demand, the two-phase timeout armed, the job's own work under an optional transaction, output guards, and one terminal event. Upstream throttling, a truncated answer and a correctable answer re-run the attempt transparently; a cancellation and a timeout end it. The dispatcher also owns the message bus, the admission monitor, the heartbeat engine, the spend gates and the compliance envelope, and stops all of them at shutdown. harness/PACKAGE.md states the contract; the section "The dispatch contract" carries the numbers.
Since:
0.1 (2025-09-18)
Author:
Andrey Santrosyan
  • Enum Constant Details

  • Field Details

    • DEFAULT_SHUTDOWN_TIMEOUT_MS

      public static final long DEFAULT_SHUTDOWN_TIMEOUT_MS
      The graceful drain window a shutdown(long) caller uses when it has no deployment-specific number.
      See Also:
  • Method Details

    • values

      public static JobDispatcher[] values()
      Returns an array containing the constants of this enum class, in the order they are declared.
      Returns:
      an array containing the constants of this enum class, in the order they are declared
    • valueOf

      public static JobDispatcher valueOf(String name)
      Returns the enum constant of this class with the specified name. The string must match exactly an identifier used to declare an enum constant in this class. (Extraneous whitespace characters are not permitted.)
      Parameters:
      name - the name of the enum constant to be returned.
      Returns:
      the enum constant with the specified name
      Throws:
      IllegalArgumentException - if this enum class has no constant with the specified name
      NullPointerException - if the argument is null
    • getInstance

      public static JobDispatcher getInstance()
      The one instance, under the name callers read most naturally; the same object as INSTANCE.
    • sealComplianceEnvelope

      public void sealComplianceEnvelope(ComplianceEnvelope envelope)
      Seals the envelope - once, permanently. A second seal throws.
    • getComplianceEnvelope

      public ComplianceEnvelope getComplianceEnvelope()
      The sealed envelope. A read before any seal returns the refusing default WITHOUT sealing, so an early reader gets deterministic default-deny and the servlet's later legitimate seal still lands.
    • registerSpendGate

      public void registerSpendGate(SpendGate gate)
    • submit

      public <T> JobHandle<T> submit(Job<T> job)
      Submits a job for execution without dependencies. Gets userId from job.getUserId() (via Identifiable interface).
      Type Parameters:
      T - the job's return type
      Parameters:
      job - the job to submit
      Returns:
      a handle to monitor and control the job
    • submit

      public <T> JobHandle<T> submit(Job<T> job, Map<String,Object> initialMetadata)
      Submits a job for execution with initial metadata seeded into the job's context. The metadata is seeded before any lifecycle event (JobScheduled, JobStartedEvent, TerminalEvent) fires for the job, so all downstream observers see the seeded keys in the snapshot's metadata map.

      The dispatcher is semantically opaque about the contents: it forwards the map into the child's JobContext via JobContext.putMetadata(String, Object) and does not interpret any key. Callers choose the key namespace (e.g. AbstractOrchestrator.META_ITERATION, Tool.OBS_INPUT).

      Type Parameters:
      T - the job's return type
      Parameters:
      job - the job to submit
      initialMetadata - metadata entries to seed into the job's context, or null for none
      Returns:
      a handle to monitor and control the job
    • submit

      public <T,D> JobHandle<T> submit(Job<T> job, JobHandle<D> dependency)
      Submits a job with a single typed dependency. Type-safe method where the dependency type D is captured at compile time.

      Usage Example:

      JobHandle<Data> dataHandle = dispatcher.submit(extractJob);
      JobHandle<Report> reportHandle = dispatcher.submit(reportJob, dataHandle);
      // reportJob can access Data result via context.singleDependencyResult()
      
      Type Parameters:
      T - the job's return type
      D - the dependency's return type
      Parameters:
      job - the job to submit
      dependency - the single job that must complete first
      Returns:
      a handle to monitor and control the job
    • submit

      public <T,D> JobHandle<T> submit(Job<T> job, List<JobHandle<D>> dependencies)
      Submits a job with multiple dependencies.

      For homogeneous dependencies (all same type D):

      List<JobHandle<Data>> dataHandles = List.of(h1, h2, h3);
      JobHandle<Report> report = dispatcher.submit(synthJob, dataHandles);
      // Inside synthJob.execute():
      List<Data> allData = context.allDependencyResults();
      

      For heterogeneous dependencies (mixed types):

      List<JobHandle<?>> mixedHandles = List.of(dataHandle, configHandle, statusHandle);
      JobHandle<Report> report = dispatcher.submit(synthJob, mixedHandles);
      // Inside synthJob.execute():
      Map<JobSnapshot, Object> results = context.getDependencyResults();
      for (var entry : results.entrySet()) {
          if (entry.getKey().jobClass() == DataJob.class) {
              Data data = (Data) entry.getValue();
          }
      }
      
      Type Parameters:
      T - the job's return type
      D - the dependency type (for homogeneous), or ? for heterogeneous
      Parameters:
      job - the job to submit
      dependencies - list of jobs that must complete first
      Returns:
      a handle to monitor and control the job
    • submit

      public <T> JobHandle<T> submit(Job<T> job, Map<String,Object> initialMetadata, List<? extends JobHandle<?>> dependencies)
      Submits a job with initial metadata and dependencies - the full form the two simpler overloads delegate to. Orchestrators use it to stamp their bookkeeping metadata onto dependency-sequenced children.
      Type Parameters:
      T - the job's return type
      Parameters:
      job - the job to submit
      initialMetadata - metadata visible on the context from the start, or null
      dependencies - jobs that must complete first, or null
      Returns:
      a handle to monitor and control the job
    • submitWithDelay

      public <T> CompletableFuture<JobHandle<T>> submitWithDelay(Job<T> job, Duration delay)
      Submits a job after a delay using a virtual thread. The delay allows parent transactions to commit before the job starts, solving race conditions where a job needs to see committed data.

      For root-level jobs only: the delayed submission happens on a fresh virtual thread, which is not any live job's executing thread, so the submission door admits it only when the job's parent is not a live job - exactly the shape of a workflow root. An orchestrator that wants delayed work inside its subtree sequences it behind a dependency instead.

      Usage Example:

      // Submit job with 500ms delay to ensure transaction commits
      dispatcher.submitWithDelay(
          new ReindexJob(root, documentId),
          Duration.ofMillis(500)
      ).thenAccept(handle -> {
          log.info("Job started: {}", handle.getJobId());
      });
      
      Type Parameters:
      T - the job's return type
      Parameters:
      job - the job to submit
      delay - the delay before submission (null, zero, or negative means immediate)
      Returns:
      CompletableFuture that completes with the JobHandle after the delay
    • start

      public void start()
      Starts the dispatcher. Schedulers are started on demand when jobs are submitted.
    • shutdown

      public void shutdown(long timeoutMs)
      Shuts down the dispatcher and all active schedulers.
      Parameters:
      timeoutMs - maximum time to wait for shutdown
    • isRunning

      public boolean isRunning()
      Checks if the dispatcher is running.
    • registerForShutdown

      public void registerForShutdown(Stoppable stoppable)
      Registers a component for graceful shutdown.
    • getMessageBus

      public MessageBus getMessageBus()
      Gets the message bus for event subscription. Public to allow advanced usage, but prefer using the subscription methods.
    • getHeart

      public Heart getHeart()
      The heartbeat engine, for operator surfaces (store inspection, cancellation).
    • scheduleHeartbeat

      public void scheduleHeartbeat(ScheduleHeartbeat spec, String userId)
      The authority-bearing heartbeat entry for code OUTSIDE any job - boot wiring, an operator endpoint with an authenticated session. Demands a principal exactly like Job.workflow; the platform threat model trusts code, so a trusted caller naming a principal here is the same posture as every root-workflow submission. Jobs never call this: an orchestrator schedules by publishing the spec through JobContext.publish, which captures its identity and sealed guard; a non-orchestrator cannot schedule at all.
    • subscribe

      public <T extends JobEvent> MessageBus.Subscription subscribe(JobObserver<T> observer, Class<T> eventType)
      Subscribes an observer to job events. This is the main public API for event subscription.
      Type Parameters:
      T - the event type
      Parameters:
      observer - the observer to register
      eventType - the type of events to observe
      Returns:
      a subscription handle that can be used to unsubscribe
    • subscribe

      public <T extends JobEvent> MessageBus.Subscription subscribe(JobObserver<T> observer, Class<T> eventType, Class<? extends Job> jobType)
      Subscribes an observer to job events from specific job types.
      Type Parameters:
      T - the event type
      Parameters:
      observer - the observer to register
      eventType - the type of events to observe
      jobType - the job type to filter by (null for all job types)
      Returns:
      a subscription handle that can be used to unsubscribe
    • observeWorkflow

      public MessageBus.Subscription observeWorkflow(String workflowId, JobObserver<JobEvent> observer)
      Subscribes an observer to all events from a specific workflow. This is a convenience method that creates a filtered observer for workflow events.
      Parameters:
      workflowId - the workflow ID to observe
      observer - the observer to handle workflow events
      Returns:
      a subscription handle that can be used to unsubscribe
    • observeWorkflow

      public <T extends JobEvent> MessageBus.Subscription observeWorkflow(AbstractWorkflowObserver<T> observer, Class<T> eventType)
      Subscribes an AbstractWorkflowObserver to its workflow's events. This method automatically sets the subscription on the observer for self-cleanup.
      Type Parameters:
      T - the event type the observer handles
      Parameters:
      observer - the workflow observer to subscribe
      eventType - the class of events to observe
      Returns:
      a subscription handle that can be used to unsubscribe
    • cancel

      public boolean cancel(String jobId, String reason)
      Cancels a job; JobHandle.cancel(String) calls this. A job still in a queue leaves it, is recorded CANCELLED, and its waiters are released with a JobCancelledException. A running job is signalled through its context, and its own unwinding settles the state, the event and the handle. A caller waiting on the handle gets an ExecutionException whose cause is JobCancelledException.
      Parameters:
      jobId - the ID of the job to cancel
      reason - the cancellation reason
      Returns:
      true if the job was found and cancellation was initiated
    • cancelWorkflow

      public int cancelWorkflow(String workflowId, String reason)
      Cancels all jobs belonging to a workflow.

      This method cancels all running and queued jobs that share the specified workflowId. Useful for fail-fast scenarios where one job failure should abort the entire workflow.

      Parameters:
      workflowId - the workflow ID to cancel
      reason - the cancellation reason
      Returns:
      the number of jobs cancelled
    • getStatistics

      public Map<String,Object> getStatistics()
      Gets statistics for the unified execution system.