Skip to content

work-unit: control plane — input lifecycle status wiring #1415

Closed

Description

@strawgate

work-unit: control plane — input lifecycle status wiring

Purpose

Wire input-side lifecycle truth into the shared control-plane model after the shared status types and probe semantics are established.

This batch is intentionally downstream of #1414 and #1413: it plugs receiver and tailer lifecycle state into the control-plane surface rather than defining that surface.

Repo footprint

  • crates/logfwd-io/src/input.rs
  • crates/logfwd-io/src/framed.rs
  • crates/logfwd-io/src/otlp_receiver.rs
  • crates/logfwd-io/src/arrow_ipc_receiver.rs
  • crates/logfwd-io/src/tail.rs or adjacent tail modules touched by lifecycle wiring
  • crates/logfwd/src/pipeline.rs
  • targeted input / diagnostics tests

In scope

# Type Why included
#1306 architecture input-side lifecycle is part of the shared control-plane substrate
#1310 architecture tailer lifecycle should feed the shared status model
#1311 architecture receiver lifecycle should become explicit instead of thread-lifetime inference

Related metas / phases

  • should follow #1414 shared status model and #1413 probe truth
  • broader I/O umbrella: #1315
  • temporary cleanup-wave coordination only: #1450

Non-goals

  • no sink-side degradation or failure wiring (that stays in #1416)
  • no full receiver substrate rewrite or axum migration
  • no full tailer modularization / typestate implementation
  • no retry/backoff semantics changes

Done when

  • OTLP, Arrow IPC, framed inputs, and tailer-owned inputs report explicit lifecycle state through the shared model
  • quiet-but-healthy or idle inputs do not fail readiness by themselves
  • start, stop, and fatal input failure transitions are visible in diagnostics
  • tests cover representative healthy, idle, stopping, and failed input states

Activity

  1. added
    enhancementNew feature or request
    productionRequired for production readiness
    P2: mediumMinor bug, missing validation, metric inaccuracy
    work-unitScheduling ticket for one agent run
    architectureSystemic design improvements that eliminate classes of bugs
    on Apr 6, 2026
  2. github-actions commented on Apr 6, 2026

    @github-actions
    Contributor

    tl;dr: Outcome A — ready for implementation: input lifecycle state is currently invisible at the shared control-plane boundary, and this can be fixed mechanically by adding per-input lifecycle status to shared diagnostics and wiring explicit transitions in the input loops/receivers.

    Recommendation

    Implement this as a focused wiring slice: add a shared input lifecycle state model, attach it to PipelineMetrics input entries, emit transitions from input poll loops + receiver shutdown/error paths, and expose state in diagnostics JSON while preserving the current quiet-source readiness rule.

    Findings

    Core gaps (verified in code):

    • crates/logfwd-io/src/input.rs:43 (pub trait InputSource: Send) has only poll, name, checkpoint_data, set_offset_by_source; there is no lifecycle/status API.
    • crates/logfwd-io/src/diagnostics.rs:39 stores pipeline inputs as Vec<(String, String, Arc(ComponentStats))> (name/type/stats only).
    • crates/logfwd-io/src/diagnostics.rs:545-555 readiness is let ready = !self.pipelines.is_empty(); (no per-input health/lifecycle influence).
    • crates/logfwd-io/src/diagnostics.rs:1650-1655 test explicitly asserts quiet/no-data pipeline remains ready.
    • crates/logfwd/src/pipeline.rs:1059-1065 poll errors are logged/slept (input.poll_error) but no lifecycle transition is published.
    • crates/logfwd-io/src/otlp_receiver.rs:279-289 and crates/logfwd-io/src/arrow_ipc_receiver.rs:239-244 return empty on no data; no shared lifecycle state updates are emitted.
    • crates/logfwd-io/src/tail.rs:759-766 emits EndOfFile (idle-like signal) but this is not surfaced into diagnostics lifecycle state.

    Related architecture issues (context):

    Verification
    $ cargo test -p logfwd-io test_ready_endpoint_ -- --nocapture
    running 2 tests
    test diagnostics::tests::test_ready_endpoint_no_pipelines_returns_503 ... ok
    test diagnostics::tests::test_ready_endpoint_with_pipeline_returns_200 ... ok
    
    test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 210 filtered out

    This confirms the current readiness contract: pipeline existence gates readiness, not data freshness.

    Detailed Action Plan (mechanical)

    Files to modify (with current anchors)

    1. crates/logfwd-types/src/diagnostics.rs:10 — pub struct ComponentStats
    2. crates/logfwd-io/src/diagnostics.rs:39 — pub inputs: Vec<(String, String, Arc(ComponentStats))>
    3. crates/logfwd/src/pipeline.rs:1316 — fn build_input_state(...) -> Result(InputState, String)
    4. crates/logfwd/src/pipeline.rs:1038 and :1195 — both input poll loops
    5. crates/logfwd-io/src/otlp_receiver.rs:278 — impl InputSource for OtlpReceiverInput
    6. crates/logfwd-io/src/arrow_ipc_receiver.rs:32 — pub struct ArrowIpcReceiver / receiver lifecycle hooks
    7. crates/logfwd-io/src/input.rs:43 — pub trait InputSource: Send

    Exact changes

    1. Add shared input lifecycle model in logfwd-types

      • In crates/logfwd-types/src/diagnostics.rs, add:
        • enum InputLifecycleState { Starting, Healthy, Idle, Stopping, Stopped, Failed }
        • small lock-free holder/snapshot fields for state, reason (optional), and state_changed_at_ns.
      • Keep API minimal and default-safe (no broad fallbacks).
    2. Attach lifecycle to per-input diagnostics entries

      • In crates/logfwd-io/src/diagnostics.rs, replace input tuple storage with a named struct (e.g. InputMetricsEntry) containing:
        • name, type, stats, lifecycle.
      • Update /api/pipelines JSON serializer to include input lifecycle fields (state, reason, state_changed_at_ns).
    3. Wire lifecycle handle through pipeline input construction

      • In crates/logfwd/src/pipeline.rs:
        • extend InputState to include lifecycle handle.
        • in build_input_state, initialize Starting then set Healthy once source is successfully constructed.
    4. Emit transitions in both input loops (input_poll_loop, input_poll_loop_async)

      • On events.is_empty() following prior healthy activity: set Idle.
      • On data receipt: set Healthy.
      • On poll error branch (input.poll_error): set Failed with reason.
      • On shutdown path before loop break/drain send: set Stopping, then Stopped after drain send attempt.
    5. Receiver-specific stop/failure visibility

      • In crates/logfwd-io/src/otlp_receiver.rs and crates/logfwd-io/src/arrow_ipc_receiver.rs:
        • ensure receiver teardown paths (Drop) can surface Stopping/Stopped through shared lifecycle handle.
        • for disconnected channel conditions in poll, propagate explicit error instead of silently appearing idle.
    6. Preserve quiet-source readiness semantics

      • Keep /ready semantics such that Idle does not fail readiness.
      • readiness should fail only when process/pipeline has fatal lifecycle states per current scope.

    Test to write/update

    1. crates/logfwd-io/src/diagnostics.rs tests:

      • extend test_pipelines_endpoint style assertions to verify lifecycle fields are present for each input.
      • add coverage for representative states: healthy, idle, stopping, failed.
      • retain existing quiet-source readiness behavior (test_ready_endpoint_with_pipeline_returns_200).
    2. crates/logfwd/src/pipeline.rs tests:

      • add focused unit tests for lifecycle transitions in input loops (data->idle, error->failed, shutdown->stopping/stopped).
    3. Receiver tests:

      • crates/logfwd-io/src/otlp_receiver.rs / arrow_ipc_receiver.rs: assert disconnect/stop transitions are reflected.

    Verification commands

    cargo test -p logfwd-io
    cargo test -p logfwd --lib pipeline
    Related Items
    Type Link Relevance
    Issue #1415 This work-unit
    Issue #1306 Shared lifecycle/readiness/status substrate this wiring plugs into
    Issue #1310 Tailer lifecycle architecture source
    Issue #1311 Receiver lifecycle architecture source
    File crates/logfwd-io/src/input.rs:43 Input boundary lacks lifecycle/status surface
    File crates/logfwd-io/src/diagnostics.rs:39 Inputs stored as counters-only tuples
    File crates/logfwd/src/pipeline.rs:1059 Poll errors not wired into lifecycle state
    PR (open) #1378 Overlaps receiver shutdown/lifecycle paths
    PR (open) #1402 Overlaps pipeline.rs control flow
    PR (open, draft) #1370 Touches nearby input/framing/pipeline surfaces

    Note

    🔒 Integrity filtering filtered 10 items

    Integrity filtering activated and filtered the following items during workflow execution.
    This happens when a tool call accesses a resource that does not meet the required integrity or secrecy level of the workflow.


    What is this? | From workflow: Issue Triage

    Give us feedback! React with 🚀 if perfect, 👍 if helpful, 👎 if not.

  3. added
    component:input/commonCross-cutting input behavior spanning multiple input types
    component:diagnosticsDiagnostics endpoints, dashboard, health, probes, and trace explorer
    on Apr 6, 2026
  4. changed the title [-]work-unit: logfwd-io inputs — lifecycle status wiring for receivers and tailers[/-] [+]work-unit: control plane — input lifecycle status wiring[/+] on Apr 6, 2026
  5. added
    component:pipelinePipeline orchestration, batching, runtime flow, and worker coordination
    on Apr 6, 2026
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

    P2: mediumMinor bug, missing validation, metric inaccuracyarchitectureSystemic design improvements that eliminate classes of bugscomponent:diagnosticsDiagnostics endpoints, dashboard, health, probes, and trace explorercomponent:input/commonCross-cutting input behavior spanning multiple input typescomponent:pipelinePipeline orchestration, batching, runtime flow, and worker coordinationenhancementNew feature or requestproductionRequired for production readinesswork-unitScheduling ticket for one agent run

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions