Repository navigation
Generate audit and saga load against a ServiceControl.Audit instance - #5969
Open
johnsimons wants to merge 2 commits into
Open
johnsimons wants to merge 2 commits into
johnsimons wants to merge 2 commits into
Conversation
…ing tool Extends the testing tool to drive ServiceControl.Audit ingestion, not just error ingestion. The new writer sends audit envelopes straight to the audit queue, including whole saga episodes (New/Updated/Completed messages plus their snapshots) linked via InvokedSagas/SagaStateChange headers so the audit instance can resolve saga history and drill-through. Also wires audit instances in the AppHost to the same SQL Server/PostgreSQL backend as the primary via EF persistence, with ingestion tuning, OTel export and custom-check reporting to the primary, and extends the Grafana dashboard and docs to cover the new audit load paths.
Updates Aspire.Hosting.* packages and the AppHost SDK to 13.6.1, enables the CLI bundle, and adds appsettings.json for logging configuration. Also changes the default audit-instances option from 0 to 1 so audit load is exercised out of the box.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The harness only drives error ingestion today. This adds the audit side: a direct audit-queue writer, an Aspire audit instance running on EF persistence, and audit series on the Grafana dashboard beside the error ones.
Audit ingestion lives in the
ServiceControl.Auditinstance rather than the primary, so the load targets the audit container's own queue.Direct audit-queue writer
New endpoints alongside the existing bypass writer:
POST /api/audit-bypass/startwith{ "rate": 100, "parallelism": 4, "sagaSnapshotRatio": 0.2, "durationSeconds": 60 }POST /api/audit-bypass/stopGET /api/audit-bypass/statusMost claims emit one processed-message envelope carrying the headers a real endpoint would have stamped:
NServiceBus.ProcessingEndpoint, the host ids, andTimeSent,ProcessingStartedandProcessingEndedspread so delivery, processing and critical times are not zero. They rotate across a pool of simulated endpoints, message types and conversations.The writer shares the error writer's pacing.
BypassRunis split into aLoadRunbase holding the clock, the shared claim budget andAchievedRate, withBypassRunadding the scenario.DirectErrorQueueWriterbehaviour is unchanged.Saga episodes
A share of claims emit a whole saga episode instead: the three messages that drove one saga through New, Updated and Completed, each followed by the snapshot it produced. One worker writes the episode so the phases reach the queue in order.
The links between the pieces are strict, and getting any of them wrong fails quietly:
NServiceBus.InvokedSagas(SagaType:SagaId) andServiceControl.SagaStateChange(SagaId:New|Updated|Completed).InvokedSagasParseris the only path by which an audited message is attached to a saga, and it runs at query time insideToMessagesView, so a malformed value throws after the rows are already stored.Initiator.InitiatingMessageIdis the id of the message directly before it, so drill-through from the saga view resolves to a real audited message.EnclosedMessageTypesheader is the bare unqualified type name.AuditPersistercompares that header with==, so an assembly-qualified value is stored as an ordinary audit row with no error and no saga history.sagaSnapshotRatiois snapshots per processed message. The default0.2emits two snapshots for every ten processed messages, and0disables episodes.AppHost
--audit-instancesnow gives each audit instance EF persistence under the audit settings namespace (SERVICECONTROL_AUDIT_PERSISTENCETYPE,SERVICECONTROL_AUDIT_DATABASE_CONNECTIONSTRING), OTLP export, audit-namespaced ingestion tuning, andServiceControlQueueAddressso its custom checks and failed audit imports reach the primary. No body storage is configured, because the audit EF persisters store bodies inline.The first audit instance runs
SetupAndRunand owns the migrations. Later instances run and wait for it, so several instances on one database do not race EF migrations. Partition provisioning continues from the retention sweep.--audit-instancesstays defaulted to 0. Asking for audit instances on SQL persistence without--tagprints a warning, because the audit EF persisters are newer than the latest release and the defaultparticular/servicecontrol-audit:latestimage does not contain them.Dashboard
Ingestion panels carry audit series beside the error ones, labelled
error:andaudit:, using the existing smoothing idiom. Audit message categories areaudit-message,saga-updateandcontrol-message, so the audit targets filter on those rather thanfailed-message.Some panels deliberately differ. The audit instance emits no
sc.audit.ingestion.storage_duration_seconds, so the storage write and storage share panels stay error only and say so in their descriptions. The audit heatmap is its own panel, since two bucket distributions on one heatmap are unreadable. Batch outcome share puts audit in a separate stacking group, because each share sums to 1 on its own.Verification
A harness compiled against the real
SagaAuditMessagesSerializationContext,SagaSnapshotFactoryandInvokedSagasParserasserts 63 properties of the generated messages: bodies deserialize, the saga-link headers parse to the right status, snapshot and message agree on saga id and type, initiating ids resolve, phases order with increasing finish times, times come backKind=Utc, and the ratio arithmetic produces the requested mix.A LearningTransport run wrote 548 processed messages and 108 snapshots covering 36 sagas, spread across all six simulated endpoints and all three saga types, with every message id distinct and the headers intact on the wire.
Known limitation
Running audit load on SQL Server or PostgreSQL needs an audit image containing the EF audit persisters. Until the next release that means
--tagwith a prerelease, or a locally built image.