Skip to content

feat(audit): wire async-queue-capacity property to a bounded executor#22

Merged
jlc488 merged 1 commit into
mainfrom
feat/audit-async-queue-wiring
May 30, 2026
Merged

feat(audit): wire async-queue-capacity property to a bounded executor#22
jlc488 merged 1 commit into
mainfrom
feat/audit-async-queue-wiring

Conversation

@jlc488
Copy link
Copy Markdown
Contributor

@jlc488 jlc488 commented May 27, 2026

Follow-up #4/5. #18 exposed devslab.kit.audit.async-queue-capacity on the Settings endpoint but the property wasn't actually wired to anything — the audit publisher was synchronous. This PR makes it real.

Property

  • DevslabKitProperties.Audit.asyncQueueCapacity (default 1024). The Settings endpoint already surfaces this value, so the number admins see on the page is now the number the runtime actually uses.

Executor

AuditAutoConfiguration registers a ThreadPoolTaskExecutor bean named devslabKitAuditPersistenceExecutor:

  • core=1 / max=1 — audit writes are tiny; one worker is enough and avoids starving the main pool.
  • Bounded LinkedBlockingQueue sized from devslab.kit.audit.async-queue-capacity.
  • CallerRunsPolicy on rejection: when the queue saturates, the request thread runs the write inline. Slow request, but no audit row is ever lost.
  • waitForTasksToCompleteOnShutdown=true with a 10s grace, so in-flight events flush during graceful shutdown.

Publisher

DefaultAuditEventPublisher constructor now takes an Executor:

  • Persistence write (AuditLogService.record) runs on the executor — request thread returns without the DB round-trip.
  • Spring ApplicationEventPublisher fanout stays synchronous so @EventListener handlers on the request thread (e.g. metrics counters) still see the event before the request returns.

Backward compatibility

DefaultAuditEventPublisher constructor signature changed (added Executor). The only call-site is AuditAutoConfiguration, updated in this same PR. No consumer code outside this repo constructs DefaultAuditEventPublisher directly today.

Test plan

  • ./gradlew build green (55 tasks; sample-app context loads and runs the smoke test using the new async publisher)
  • Stress: hammer an endpoint that publishes audit events at >1024 RPS sustained, watch the request thread time-series climb proportionally (CallerRunsPolicy kicking in), and confirm no rows are dropped in platform_audit_log

Follow-up #4/5 to the contract-gap series. #18 exposed
`devslab.kit.audit.async-queue-capacity` on the Settings endpoint
but the property wasn't actually wired to anything — the audit
publisher was synchronous. This PR makes it real.

Property
--------
- DevslabKitProperties.Audit gains asyncQueueCapacity (default
  1024). Settings endpoint already surfaces this value, so the
  number admins see on the Settings page is now the number the
  runtime actually uses.

Executor
--------
- AuditAutoConfiguration registers a ThreadPoolTaskExecutor bean
  named "devslabKitAuditPersistenceExecutor":
    * core=1 / max=1 — audit writes are tiny, one worker is
      enough and avoids starving the main pool.
    * bounded LinkedBlockingQueue sized from
      devslab.kit.audit.async-queue-capacity.
    * CallerRunsPolicy on rejection: when the queue saturates,
      the request thread runs the write inline. Slow request,
      but no audit row is ever lost.
    * waitForTasksToCompleteOnShutdown=true with a 10s grace,
      so in-flight events flush during graceful shutdown.

Publisher
---------
- DefaultAuditEventPublisher now takes an Executor in its
  constructor:
    * persistence write (AuditLogService.record) runs on the
      executor — request thread returns without the DB round-trip.
    * Spring ApplicationEventPublisher fanout stays synchronous
      so @eventlistener handlers on the request thread (e.g.
      metrics counters) still see the event before the request
      returns.

Backward compatibility
----------------------
- DefaultAuditEventPublisher constructor signature changed (added
  Executor). The only call-site is AuditAutoConfiguration which
  is updated in the same PR. No consumer code outside this repo
  constructs DefaultAuditEventPublisher directly today.
@jlc488 jlc488 merged commit 0e92a57 into main May 30, 2026
1 check passed
@jlc488 jlc488 deleted the feat/audit-async-queue-wiring branch May 30, 2026 06:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant