Skip to content

S31.01: Service returns a four-state servicing status #574

Description

@DavidCozens

Parent epic: #573

Purpose

Change SolidSyslog_Service() from void to returning enum SolidSyslogServiceStatus, so a host can drive an event-driven loop (wake on work, back off on a down sender) instead of a fixed-delay poll. No new OS surface — the integrator owns the wake/sleep mechanism in a thin wrapper around Log/Service.

Contract

enum SolidSyslogServiceStatus:

State Meaning Returned when Host action
SOLIDSYSLOG_SERVICE_HALTED store wedged, nothing can be processed store is halted (existing IsServiceEnabled guard) integrator-defined (alarm / slow heartbeat)
SOLIDSYSLOG_SERVICE_READY work is ready now this call's buffer drain moved ≥1 record, or the store still has unsent after a successful send loop again immediately, no wait
SOLIDSYSLOG_SERVICE_BLOCKED only the sender is stuck buffer was idle this call, a send was attempted and failed back off (wakeable by a Log signal)
SOLIDSYSLOG_SERVICE_IDLE nothing anywhere buffer idle, no send attempted/needed, store has no unsent wait for the next Log

Decision order inside Service (after the halt guard):

drained    = DrainBufferIntoStore()   -> bool: did any Buffer_Read succeed
sendFailed = SendOneFromStore()       -> reports "send attempted and failed"
if drained          -> READY    (buffer activity dominates a send failure)
if sendFailed       -> BLOCKED
if Store_HasUnsent  -> READY
else                -> IDLE

Key invariant: buffer activity out-ranks send failure — a down sender can never demote the loop out of "keep draining buffer→store" while the buffer has anything to move. BLOCKED is only reached once the buffer is idle and the sole stuck thing is the socket.

Notes

  • voidenum is source-compatible: existing poll loops that ignore the result compile unchanged. We deliberately do not add warn_unused_result.
  • Buffer gets no new API — "buffer not idle" is inferred from the drain's read results (the Buffer vtable has only Write/Read).
  • Internal: DrainBufferIntoStore and SendOneFromStore go from void to returning their outcome; Service composes them.
  • Contract documented in the Service() header comment in SolidSyslog.h. No new .md.
  • NULL handle → IDLE (the Error handler already fires).
  • Enum constants SOLIDSYSLOG_SERVICE_* (matches SOLIDSYSLOG_TRANSPORT_* shape).

TDD order (each path tested explicitly)

  1. Empty buffer + empty store → IDLE.
  2. Buffer holds a message; drain moves it → READY.
  3. Buffer holds a message and the sender fails → still READY (dominates BLOCKED).
  4. Buffer empty, store has unsent, send fails → BLOCKED.
  5. Halted store → HALTED.

Test Evidence

debug preset green; explicit coverage of all four return paths.

Metadata

Metadata

Assignees

No one assigned

    Labels

    storyStory issue

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions