Mongo transaction #771
Replies: 4 comments 3 replies
-
|
Please provide more details. Are you auditing a MongoDB Entity Framework Core provider? |
Beta Was this translation helpful? Give feedback.
-
|
Oh, I see what you mean now. If your driver is connected to a MongoDB replica set, then each call to So if, within a single transaction, you insert one document and delete another, you should expect three audit events: For example: [
{
"Command": {
"RequestId": 6,
"OperationId": 2,
"CommandName": "insert",
"Body": {
"insert": "TestColl",
"ordered": true,
"$db": "TestDb",
"lsid": {
"id": "e3418622-2296-4a93-9226-408bbcd5cda2"
},
"txnNumber": 2,
"startTransaction": true,
"autocommit": false,
"documents": [
{
"_id": {
"Timestamp": 1760144078,
"CreationTime": "2025-10-11T00:54:38Z"
},
"x": 1
}
]
},
"Duration": 7,
"Success": true,
"Timestamp": "2025-10-11T00:54:38.7334268Z"
}
},
{
"Command": {
"RequestId": 7,
"Connection": null,
"OperationId": 3,
"CommandName": "delete",
"Body": {
"delete": "TestColl",
"ordered": true,
"$db": "TestDb",
"lsid": {
"id": "e3418622-2296-4a93-9226-408bbcd5cda2"
},
"txnNumber": 2,
"autocommit": false,
"deletes": [
{
"q": {},
"limit": 1
}
]
},
"Duration": 4,
"Success": true,
"Timestamp": "2025-10-11T00:54:38.7653531Z"
}
},
{
"Command": {
"RequestId": 8,
"OperationId": 4,
"CommandName": "commitTransaction",
"Body": {
"commitTransaction": 1,
"$db": "admin",
"lsid": {
"id": "e3418622-2296-4a93-9226-408bbcd5cda2"
},
"txnNumber": 2,
"autocommit": false
},
"Duration": 8,
"Success": true,
"Timestamp": "2025-10-11T00:54:38.7939639Z"
}
}
]You’ll notice the three events share the same To correlate all related events, use the logical session ID ( https://www.mongodb.com/community/forums/t/how-to-find-queries-associated-with-a-transaction/117133 |
Beta Was this translation helpful? Give feedback.
-
|
Now, if you need to save the intercepted commands after a transaction commit as a single event, you can implement your own Audit Data Provider by inheriting from AuditDataProvider (or any of the included providers). You will need custom logic to maintain a list of events for ongoing transactions. public class MyTransactionalDataProvider : AuditDataProvider
{
private readonly ConcurrentDictionary<string, ConcurrentQueue<AuditEventMongoCommand>> _commands = new();
public override object InsertEvent(AuditEvent auditEvent)
{
var mongoEvent = (AuditEventMongoCommand)auditEvent;
var cmdName = mongoEvent.Command.CommandName;
var body = (Dictionary<string, object>)mongoEvent.Command.Body;
var isStartTransaction = (bool)(body.GetValueOrDefault("startTransaction", null) ?? false);
var lsId = body.GetValueOrDefault("lsid", null) is Dictionary<string, object> dict ? dict.GetValueOrDefault("id") : string.Empty;
var txnNumber = body.GetValueOrDefault("txnNumber", string.Empty).ToString();
var tranId = $"{lsId}:{txnNumber}";
if (isStartTransaction)
{
// New transaction started with this event, add it to the list of events for this transaction
_commands[tranId] = new ConcurrentQueue<AuditEventMongoCommand>([mongoEvent]);
return null;
}
if ((cmdName == "commitTransaction" || cmdName == "abortTransaction") && _commands.TryRemove(tranId, out var eventList))
{
// Transaction ended, save all events as a single audit event
Save(eventList.ToList(), cmdName);
return null;
}
if (_commands.TryGetValue(tranId, out var list))
{
// Event belongs to an ongoing transaction, add it to the list
list.Enqueue(mongoEvent);
return null;
}
// Not part of a transaction, save single event immediately
Save(mongoEvent);
return null;
}
public async override Task<object> InsertEventAsync(AuditEvent auditEvent, CancellationToken cancellationToken = default)
{
// Same as InsertEvent but asynchronous...
throw new NotImplementedException();
}
private void Save(List<AuditEventMongoCommand> eventList, string cmdName)
{
// Save the commands in a transaction as a single audit event
// cmdName indicates whether it was a commit or abort
throw new NotImplementedException();
}
private void Save(AuditEventMongoCommand mongoEvent)
{
// Save a single command event that is not part of a transaction
throw new NotImplementedException();
}
}This implementation is provided as a conceptual example and has not been thoroughly tested. You may need to adjust it to match your specific use case and ensure proper concurrency handling, error management, and persistence logic. |
Beta Was this translation helpful? Give feedback.
-
|
There is no separate start transaction event. The first command in a transaction includes the |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Hello Dear
I want to ask you if I can save audit after commit transaction in mongodb how I can handle this
Beta Was this translation helpful? Give feedback.
All reactions