You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Parent epic: #337
Delivery step 4; depends on the architecture, interfaces and working memory baseline #338, refined pending contract/CBOR #343, and stage contract #344. Followed by file-backed stages #345.
Goal
Implement the filesystem pending-message backend and wire durable admission into HTTP/SMPP ingress. Deliver the incremental file/memory/memory profile: acknowledged messages survive process/container restart, but selected work is reselected and routed work is rerouted. #345 adds opt-in file-backed selection/routing stages. memory/memory/memory remains the non-durable default; durable profiles require explicit configuration.
Existing PostgreSQL storage continues to handle provider correlations and downstream DLR delivery. This issue does not implement file-backed router/routed state.
File layout and admission
Use stable UUIDs and bounded hash buckets for complete messages and multipart parts; keep committed files distinguishable from temporary publications. Final layout is an implementation choice.
Validate and encode the versioned CBOR envelope from feat(storage): define the outbound pending-message contract and CBOR envelope #343, write to a unique temporary file on the same filesystem, close it, and atomically publish without replacing an existing committed record. Acknowledge only after publication succeeds; report capacity/write/codec/lock failures rather than falling back to memory.
Enforce single-process ownership of the spool root; require a surviving persistent volume for container replacement. Host power-loss/fsync-level guarantees are not claimed.
Recover committed work before opening protocol admission. Ignore/clean incomplete temporary files under documented rules; fail readiness on unknown-version or corrupt committed records, identifying the record in logs.
Ingress and lifecycle
HTTP 202 and SMPP submit_sm_resp STATUS_OK follow successful store admission; storage failure returns a suitable retryable response. Preserve the existing semantic of duplicate multipart ordinal acknowledgements.
Persist every SMPP multipart part, the group identity and absolute deadline, reconstruct incomplete/complete groups on restart, and retain source records until aggregate processing is terminal. Expired incomplete groups release accepted parts for independent routing.
Keep the pending source during routing, retries, asynchronous provider work, and existing PostgreSQL DLR handoff. Terminal drops/rejections and successes complete it only after all copied branches/provider parts and required DLR work are done.
With memory-backed selected/routed stages, recovery selects and routes surviving pending work again. A crash after provider submission can duplicate delivery; source completion must not falsely claim an uncommitted DLR handoff.
Provide an exclusive spool path on the deployment's persistent volume, stopped-instance backup/restore guidance, selected-backend and recovery-summary logs, sendium-sms-storage readiness, and bounded-operation latency/error metrics. Do not log SMS payloads or add per-message metric labels.
Fail readiness when the selected durable backend cannot safely accept or recover work; never silently switch to volatile state.
Parent epic: #337
Delivery step 4; depends on the architecture, interfaces and working memory baseline #338, refined pending contract/CBOR #343, and stage contract #344. Followed by file-backed stages #345.
Goal
Implement the filesystem pending-message backend and wire durable admission into HTTP/SMPP ingress. Deliver the incremental
file/memory/memoryprofile: acknowledged messages survive process/container restart, but selected work is reselected and routed work is rerouted. #345 adds opt-in file-backed selection/routing stages.memory/memory/memoryremains the non-durable default; durable profiles require explicit configuration.Existing PostgreSQL storage continues to handle provider correlations and downstream DLR delivery. This issue does not implement file-backed router/routed state.
File layout and admission
Ingress and lifecycle
202and SMPPsubmit_sm_resp STATUS_OKfollow successful store admission; storage failure returns a suitable retryable response. Preserve the existing semantic of duplicate multipart ordinal acknowledgements.Configuration, deployment, observability
pending=file,router-queue=memory,routed-work=memoryprofile alongside the existingmemory/memory/memorybaseline from feat(storage): define outbound stage abstractions and memory baseline #338. Validate unsupported stage combinations until feat(storage): persist selected-router and routed-work state on filesystem #345 ships.memory/memory/memoryremains the default, including after feat(storage): persist selected-router and routed-work state on filesystem #345; file-backed profiles require explicit configuration.sendium-sms-storagereadiness, and bounded-operation latency/error metrics. Do not log SMS payloads or add per-message metric labels.Verification and acceptance criteria
file/memory/memory.Out of scope
File-backed router/routed state (#345), PostgreSQL outbound backend (#333), DLR backend replacement (#340/#334), durable retry scheduling/provider outcome, multi-process spool sharing, automatic memory fallback, and exactly-once provider delivery.