public async Task AddOrUpdate_callsFindAsyncAndReplaceOneAsync() { var record = new MongoRecord { Details = new Audit(TestCorrelationId, TestUser).Details }; MongoCollectionMock.Setup(x => x.FindAsync( It.IsAny <FilterDefinition <MongoRecord> >(), It.IsAny <FindOptions <MongoRecord> >(), It.IsAny <CancellationToken>())).ReturnsAsync(new TestMongoCursor <MongoRecord>(record)); MongoCollectionMock.Setup(x => x.ReplaceOneAsync( It.IsAny <FilterDefinition <MongoRecord> >(), It.IsAny <MongoRecord>(), It.IsAny <ReplaceOptions>(), It.IsAny <CancellationToken>())).ReturnsAsync(new ReplaceOneResult.Acknowledged(1, 0, new BsonString(""))); await Storage.AddOrUpdate(TestKey, TestValue); MongoCollectionMock.Verify(x => x.FindAsync( It.IsAny <FilterDefinition <MongoRecord> >(), It.IsAny <FindOptions <MongoRecord> >(), It.IsAny <CancellationToken>()), Times.Once); MongoCollectionMock.Verify(x => x.InsertOneAsync( It.IsAny <MongoRecord>(), It.IsAny <InsertOneOptions>(), It.IsAny <CancellationToken>()), Times.Never); MongoCollectionMock.Verify(x => x.ReplaceOneAsync( It.IsAny <FilterDefinition <MongoRecord> >(), It.IsAny <MongoRecord>(), It.IsAny <ReplaceOptions>(), It.IsAny <CancellationToken>()), Times.Once); }
public async Task Publish(object message, CancellationToken token) { var messageName = typeEncoder.Encode(message.GetType()) ?? throw new NotSupportedException($"Not supported message type '{message.GetType()}'."); var messageId = message.GetSha1(); var audit = new Audit { CorrelationId = context.CorrelationId, Requested = clock.UtcNow, User = context.User }; var requested = new MongoRecord(messageId, messageName, message, audit); await InsertOne(requested, token); }
private async Task InsertOne(MongoRecord record, CancellationToken token) { try { await collection.InsertOneAsync( record, new InsertOneOptions(), token); } catch (MongoWriteException ex) when(ex.WriteError.Category == ServerErrorCategory.DuplicateKey) { logger.LogDebug("Message({MessageName}/{MessageId}) polling: already requested.", record.MessageName, record.Id); } }
/// <inheritdoc/> public async Task Update(MongoRecord record, CancellationToken token) { try { var result = await collection.ReplaceOneAsync( filter : x => x.Id == record.Id && x.Status == HandlingStatus.Requested, record, new ReplaceOptions(), token); if (result.MatchedCount == 0) { logger.LogWarning("Message({MessageType}/{MessageId}) handling: already responded concurrently.", record.MessageName, record.Id); } } catch (Exception ex) { logger.LogError(ex, "Message({MessageType}/{MessageId}) handling: write error.", record.MessageName, record.Id); } }
/// <inheritdoc/> public async Task <Option <MongoRecord> > Process(MongoRecord record, CancellationToken token) { logger.LogInformation("Message({MessageName}/{MessageId}) handling: started.", record.MessageName, record.Id); try { var client = clientFactory.Create(MongoOptionsNames.DefaultName); var response = await client.RequestObject(record.Message, token); return(record.Succeed(response, clock.UtcNow).AsOption()); } catch (Exception ex) { var clientOptions = options.Get(MongoOptionsNames.DefaultName); if (ex is MessageDeferredException or TimeoutException or OperationCanceledException || clientOptions.TransientExceptions.Any(x => x.IsInstanceOfType(ex))) { logger.LogInformation(ex, "Message({MessageType}/{MessageId}) handling: deferred or transient error.", record.MessageName, record.Id); return(Option.None); } logger.LogError(ex, "Message({MessageType}/{MessageId}) handling: permanent error.", record.MessageName, record.Id); return(record.Fail(converter.ConvertTo(ex) !, clock.UtcNow).AsOption()); } }