Skip to content

Commands fan out per source, then reassemble N acks by count #1268

Description

@SimonHeybrock

JobOrchestrator turns one user action into N command messages — one per source, all
sharing a message_id — and then reassembles the N acknowledgements by counting them.

Both producers do it:

  • commit_workflow builds one WorkflowConfig per staged source and registers
    expected_count=len(state.staged_jobs).
  • _send_job_commands (stop/reset) builds one JobCommand per JobId and registers
    expected_count=len(state.current.jobs).

PendingCommandTracker exists for that accumulation: expected_count, success_count,
error_count, is_complete, and expiry for the responses that never arrive. A worker
handles its sources in a synchronous loop and knows the outcome for all of them at once,
so the fan-out buys nothing — it splits one synchronous result into N Kafka round-trips
and N acks, then spends dashboard state putting them back together.

One command carrying its source set, acknowledged once per worker, removes the
accumulation. In the single-worker deployment we run today that is one ack per command,
and the tracker collapses to a timeout. Multi-worker needs the ack to name the sources
it covers, so the client tracks coverage instead of a count.

What each command needs:

  • WorkflowConfig would carry the per-source config set (dict[SourceName, JobConfig]),
    which is what WorkflowState.staged_jobs already holds.
  • Stop and reset already have selector targeting: JobCommand supports workflow_id
    (what NICOS uses for reset, ADR 0006) and broadcast, and JobManager._perform_action
    returns the affected count. The dashboard is the only producer still enumerating
    JobIds.

To settle as part of it: whether partial failure reports per-source detail or just fails
the command, and whether stop keeps per-source targeting at all — ADR 0006 rejected a
per-source reset selector as unneeded, but stop_workflow's orphan sweep currently
leans on per-JobId stops.

Extracted from #445. This is the part of that design that stands on its own: it needs
the config message to carry its source set, but not the config/start split, whose
premise ADR 0006 settled the other way.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:wireKafka topics, message schemas, command/reply contracts, incl. toward NICOS/ECDCdesignOpen architecture question, no agreed solution yet

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions