Skip to content

Batch oversized bulk operation audit logs#5484

Open
Copilot wants to merge 6 commits intomainfrom
copilot/handle-large-audit-logs
Open

Batch oversized bulk operation audit logs#5484
Copilot wants to merge 6 commits intomainfrom
copilot/handle-large-audit-logs

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 6, 2026

Description

Bulk delete and bulk update audit logs concatenate all affected resource IDs into a single "Affected Items" string, which can exceed the 16,000 character log limit. This change splits the items into size-bounded batches, emitting multiple LogAudit calls as needed.

  • Created a shared BulkOperationAuditLogHelper static class in Features/Persistence/ containing the batching logic and size constants
  • Added MaxAuditLogSize (16000) and AuditLogOverheadSize (1000) constants
  • CreateAffectedItemBatches() splits items into batches where each batch string stays under the limit; items are never split mid-entry
  • A single oversized item (e.g., extremely long resource ID) is kept in its own batch rather than truncated
  • Items within a batch are comma-separated, with no leading comma on the first item
  • Updated DeletionService.CreateAuditLog() to use the shared helper
  • Updated BulkUpdateService.CreateAuditLog() to use the shared helper, replacing the previous unbounded Aggregate approach with size-safe batching

Related issues

Bug 188287

Testing

Added 8 unit tests in BulkOperationAuditLogHelperTests.cs covering: empty list, small list (single batch), large list (multi-batch), boundary sizing, include-tag preservation, no leading comma per batch, single oversized item, and no-data-loss across batches.

Added integration tests verifying the audit logging helper is invoked by both services:

  • DeletionServiceAuditLogTests.cs: GivenBulkHardDelete_WhenResourcesAreDeleted_ThenAuditLoggerIsCalledWithBatchedAffectedItems — exercises the full DeleteMultipleAsync hard-delete flow and asserts _auditLogger.LogAudit is called with "Affected Items" in additionalProperties.
  • BulkUpdateServiceTests.cs: UpdateMultipleAsync_WhenResultsReturned_ThenAuditLoggerIsCalledWithBatchedAffectedItems — exercises the UpdateMultipleAsync flow and asserts the same.

Both integration tests use a polling pattern (instead of hard-coded delays) to deterministically wait for Task.Run-based audit logging to complete.

FHIR Team Checklist

  • Update the title of the PR to be succinct and less than 65 characters
  • Add a milestone to the PR for the sprint that it is merged (i.e. add S47)
  • Tag the PR with the type of update: Bug, Build, Dependencies, Enhancement, New-Feature or Documentation
  • Tag the PR with Open source, Azure API for FHIR (CosmosDB or common code) or Azure Healthcare APIs (SQL or common code) to specify where this change is intended to be released.
  • Tag the PR with Schema Version backward compatible or Schema Version backward incompatible or Schema Version unchanged if this adds or updates Sql script which is/is not backward compatible with the code.
  • When changing or adding behavior, if your code modifies the system design or changes design assumptions, please create and include an ADR.
  • CI is green before merge Build Status
  • Review squash-merge requirements

Semver Change (docs)

Patch

Copilot AI and others added 2 commits April 6, 2026 16:32
…ay within 16,000 char limit

Agent-Logs-Url: https://github.com/microsoft/fhir-server/sessions/20d0d51f-b8cc-4da8-9995-a01c7b432716

Co-authored-by: LTA-Thinking <17463554+LTA-Thinking@users.noreply.github.com>
…eateAffectedItemBatches

Agent-Logs-Url: https://github.com/microsoft/fhir-server/sessions/20d0d51f-b8cc-4da8-9995-a01c7b432716

Co-authored-by: LTA-Thinking <17463554+LTA-Thinking@users.noreply.github.com>

foreach (var item in items)
{
string itemString = $", {(item.included ? "[Include] " : string.Empty)}{item.resourceType}/{item.resourceId}";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Please remove the comma from the first item added to a batch.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in d145517. The first item in each batch no longer has a leading comma — commas are now only used as separators between items within a batch.

Copilot AI requested a review from LTA-Thinking April 6, 2026 18:05
@LTA-Thinking LTA-Thinking marked this pull request as ready for review April 6, 2026 18:08
@LTA-Thinking LTA-Thinking requested a review from a team as a code owner April 6, 2026 18:08
@LTA-Thinking
Copy link
Copy Markdown
Contributor

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

@LTA-Thinking LTA-Thinking added this to the FY26\Q4\2Wk\2Wk21 milestone Apr 6, 2026
@LTA-Thinking LTA-Thinking added Bug Bug bug bug. Azure API for FHIR Label denotes that the issue or PR is relevant to the Azure API for FHIR Azure Healthcare APIs Label denotes that the issue or PR is relevant to the FHIR service in the Azure Healthcare APIs No-PaaS-breaking-change No-ADR ADR not needed labels Apr 6, 2026
@codecov-commenter
Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 76.95%. Comparing base (ea948f8) to head (d145517).

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #5484      +/-   ##
==========================================
+ Coverage   76.91%   76.95%   +0.04%     
==========================================
  Files         978      978              
  Lines       35680    35694      +14     
  Branches     5356     5359       +3     
==========================================
+ Hits        27443    27470      +27     
+ Misses       6903     6892      -11     
+ Partials     1334     1332       -2     

see 12 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@apurvabhaleMS
Copy link
Copy Markdown
Contributor

@LTA-Thinking do we need to do this for Bulk update as well?

@LTA-Thinking
Copy link
Copy Markdown
Contributor

@copilot Please change the update service to use the same audit log method as bulk delete. The create audit log method can be moved to a new static class that the update service and delete service can reference.

…ass; update BulkUpdateService to use batching

Agent-Logs-Url: https://github.com/microsoft/fhir-server/sessions/a1a789ae-7398-4de7-89c9-188742ff4760

Co-authored-by: LTA-Thinking <17463554+LTA-Thinking@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 6, 2026

@copilot Please change the update service to use the same audit log method as bulk delete. The create audit log method can be moved to a new static class that the update service and delete service can...

Done in c1d4731. Extracted CreateAffectedItemBatches() and the size constants into a new BulkOperationAuditLogHelper static class under Features/Persistence/. Both DeletionService and BulkUpdateService now reference it. The BulkUpdateService.CreateAuditLog method now uses batching (replacing the old Aggregate approach), so oversized audit logs are handled for bulk update as well.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • microsofthealthoss.pkgs.visualstudio.com
    • Triggering command: /usr/bin/dotnet dotnet build src/Microsoft.Health.Fhir.R4.Core/Microsoft.Health.Fhir.R4.Core.csproj --no-restore (dns block)
    • Triggering command: /usr/bin/dotnet dotnet restore src/Microsoft.Health.Fhir.R4.Core/Microsoft.Health.Fhir.R4.Core.csproj (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI changed the title Split oversized bulk delete audit logs into batches Batch oversized bulk operation audit logs Apr 6, 2026
Copilot AI requested a review from LTA-Thinking April 6, 2026 21:05
@LTA-Thinking
Copy link
Copy Markdown
Contributor

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

@LTA-Thinking
Copy link
Copy Markdown
Contributor

@copilot Please add unit tests for the deletion service that include a test showing the audit logging helper is being called. Also, update the bulk update service's unit tests to add one showing the audit logging helping is being called.

Copilot AI and others added 2 commits April 6, 2026 21:31
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 6, 2026

@copilot Please add unit tests for the deletion service that include a test showing the audit logging helper is being called. Also, update the bulk update service's unit tests to add one showing the a...

Done in dc278bd. Added DeletionServiceAuditLogTests.cs with a test GivenBulkHardDelete_WhenResourcesAreDeleted_ThenAuditLoggerIsCalledWithBatchedAffectedItems that exercises the full DeleteMultipleAsync flow and verifies _auditLogger.LogAudit is called with "Affected Items" in additionalProperties. Also added UpdateMultipleAsync_WhenResultsReturned_ThenAuditLoggerIsCalledWithBatchedAffectedItems to BulkUpdateServiceTests.cs with the same verification for the update path. Both tests use a polling pattern instead of hard-coded delays to wait for the Task.Run-based audit logging.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • microsofthealthoss.pkgs.visualstudio.com
    • Triggering command: /usr/bin/dotnet dotnet build src/Microsoft.Health.Fhir.R4.Core.UnitTests/Microsoft.Health.Fhir.R4.Core.UnitTests.csproj (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

@LTA-Thinking
Copy link
Copy Markdown
Contributor

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Azure API for FHIR Label denotes that the issue or PR is relevant to the Azure API for FHIR Azure Healthcare APIs Label denotes that the issue or PR is relevant to the FHIR service in the Azure Healthcare APIs Bug Bug bug bug. No-ADR ADR not needed No-PaaS-breaking-change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants