Repository navigation
Batch Guardian log writes and drain them on shutdown - #112
rksharma-owg wants to merge 4 commits into
Conversation
Signed-off-by: RKS <rajesh.sharma@owasp.org>
… one pass (#158) Follow-up to #157, fixing a defect I found by testing the merged workflow rather than one a reviewer would have caught from the diff. ## The defect A reconcile run that adds items cannot also set their Status. Adding an item triggers project 9's own `Item added to project` workflow, which stamps a default Status asynchronously. `apply_governance.py` builds its entire plan before executing any of it, so on a run that adds anything it has already decided the Status actions before those items exist on the board. The default lands after the run finishes and nothing corrects it until the next run. ## Measured, not theorised On the 2026-09-17 backfill the first pass made **40 adds and 1 Status change**. A second pass run immediately afterwards found **5 more Status corrections waiting**: | Item | Why the default was wrong | | --- | --- | | #135 | `status:accepted` | | #131 | `status:accepted` | | #126 | open pull request, belongs in In progress | | #113 | open pull request | | #112 | open pull request | None of those five has the default as its correct Status, which is precisely the population a single pass strands. A third pass reported zero actions, so the tool converges, it just cannot converge in one run when it is also adding. Nightly, that is up to 24 hours of a board reading Needs triage for work that is accepted or in flight. That is the failure the board exists to prevent, so shipping #157 without this would have left the automation quietly wrong in the one case it most needed to be right. ## The fix Run the board step twice under `--apply`. The dry-run path still runs once and returns, since printing the same plan twice helps nobody. The reconciler is idempotent, so the second pass costs one API listing on a run that added nothing. Once `Auto-add to project` is enabled on the project, that is every run. ## Note on review I did not admin-merge this one. #157 was merged under the administrative authorisation given for it specifically, and extending that to a second change on my own judgement is the kind of thing that should be asked for rather than assumed. The workflow is inert until the App and environment exist, so there is no urgency in merging this ahead of a normal review. Signed-off-by: Rock Lambros <rock@rockcyber.com>
|
Hi @rksharma-owg, this is a heads-up about #244, the OpenTelemetry trace exporter. It touches the same shutdown code as this PR. #244 adds a Whichever PR lands second should end up with one signal handler, the unconditional one from this PR. It should also have one memoized Nothing to change right now. I wanted both PR authors to know before it turns into a surprise merge conflict. I left the same note on #244. |
|
Since this replaces the envelope-log and session-context-log writes, could the new paths create their directory with That's the same fix Rock asked #244 to use for its OTLP file, and it closes the file-mode half of #71 inside this rewrite rather than in a follow-up that would conflict with it. |
Signed-off-by: RKS <rajesh.sharma@owasp.org>
|
@rksharma-owg, a note for when you rebase this onto |
Signed-off-by: RKS <rajesh.sharma@owasp.org>
|
This pull request's description says it closes #90, which is on the project roadmap. When it merges, GitHub closes that issue and the roadmap counts it as delivered. Please confirm the change delivers the whole issue before merging. |
|
@rocklambros, updated in a52aef5 by merging current There is now one unconditional signal handler and one memoized The two new deadline regressions fail before the correction and pass afterwards. SIGINT/SIGTERM tests cover trace export enabled and disabled. Fork validation passed for this commit and the unchanged integration baseline. The updated commit passed 1,247 Bun tests with two existing skips, type checking, and 919 Python guards in the fork. Upstream reference implementation checks and Python guards/site build also passed with the same test counts; Pages deployment is intentionally skipped for PRs. Could you please re-review the updated PR? |
President
left a comment
There was a problem hiding this comment.
@rksharma-owg hi,
Good change: decisions no longer wait for disk writes.
BUT 3 things:
- A full buffer can stop all logging until the Guardian restarts.
batchLogWritesdestroys the stream when a new record would exceed 4 MiB or 4096 records.
Queued records can be lost too.
Reproduced with a test stream taking 50 ms per write:
five ~1 MB lines at once, then one small line a second later.
Result: one "log buffer limit exceeded" error, zero lines written.
In a running Guardian, about five requests near the 1 MiB limit can cause the same failure.
The buffer fills when requests arrive faster than the disk writes them.
I'd skip and count the new record when the buffer is full:
- queued records still get written
- new records are accepted again once there is space
- a real disk error may still close the log
(#282 asks for the same recovery for trace outputs: count dropped records and recover.)
- Shutdown without traces is never tested.
The "trace export off" case intest/log-shutdown.test.tssetsACS_OTEL_FILEandACS_OTEL_ENDPOINTto "".
server.tsenables the trace exporter when either value is notundefined.
Empty strings therefore keep traces on.
Remove both keys from the child environment for this case (also the ones inherited from process.env).
Signed-off-by: RKS <rajesh.sharma@owasp.org>
President
left a comment
There was a problem hiding this comment.
@rksharma-owg - thanks, all three fixed in db8a3e8. Looks good from my side.
What changed
Guardian envelope and session-context logs currently call
appendFileSyncon the request path. Batch their existing JSONL records through bounded asynchronous append streams, and drain both streams after active requests finish during shutdown.Each sink flushes after 64 records or 100 ms from its first queued record. Queued and in-flight writes count toward limits of 4 MiB and 4,096 records. Overflow drops and counts only the new record, preserves queued records, and accepts later traffic when capacity returns. The first drop and shutdown total are reported. A real disk error disables the sink and reports once without changing the policy decision.
SIGINT and SIGTERM use one memoized
guardian.close()path, with trace export enabled or disabled. Closing refuses new ACS requests and gives active requests and both log drains one negotiated timeout (currently five seconds), then shuts down the trace exporter within its separate deadline. An expired drain is reported and pending connections are force-closed. Abrupt termination, disk errors, and expired deadlines can lose records, as documented in the Guardian README.Log schemas and record ordering stay the same; visibility is delayed. This batches existing reference-implementation logs and retains #244's OpenTelemetry exporter. It does not implement the remaining acceptance criteria of #90.
Which issue does this implement
Refs #90
Base branch
integration, because this touches a reference implementation and testsType of change
I tested this
integration:8a459524530b320c70c68d1d0b85bbcabb3771e6uv run pytest -v: 918 passed, 1 skipped locally; 919 passed on Linux in the forkuv run mkdocs build --strict: passedreference-implementations/agt,bun run typecheck: passedreference-implementations/agt,bun testwith Bun 1.3.11: 1,251 passed, 4 existing skips, 0 failed locally and in the forkThe overflow-recovery regression fails against the previous PR head and passes with the correction. Tests cover thresholds, sparse traffic, record ordering, UTF-8 byte and record limits including in-flight writes, overflow recovery, throwing reporters, disk errors, file permissions, active-request shutdown, forced deadline shutdown, and standalone SIGINT/SIGTERM with tracing on and genuinely unset tracing variables.
The four existing Bun skips cover the optional
UPSTREAM_BUNDLEcomparison and proxy/runtime regressions unsupported on Bun 1.3.11. The local Python skip requires a case-sensitive filesystem and passes on Linux.Fork preflight passed for contribution
db8a3e8b2acad30ea2cf33f7e82a2d3642aeb783and the unchanged integration baseline: complete Bun tests/type check, Python guards, strict documentation build, landing page, 44 schemas, and roadmap fixture. The baseline passed 1,231 Bun tests with the same four skips and 919 Python tests. The fork-only workflow is excluded from this PR. Upstream checks are reported separately from this fork validation.Checklist
git commit -s(required by the DCO)Security
This changes log buffering and shutdown durability. It does not change policy decisions or report a vulnerability. Buffering is bounded; records can be lost under the documented overflow, failure, and shutdown conditions.