/// <summary> /// InitializeDatabaseAsync /// </summary> /// <param name="database"></param> /// <param name="lockManager"></param> /// <returns></returns> /// <exception cref="DatabaseException"></exception> public static async Task InitializeDatabaseAsync(HB.FullStack.Database.IDatabase database, IDistributedLockManager lockManager, IEnumerable <Migration>?migrations) { GlobalSettings.Logger.LogDebug($"开始初始化数据库:{database.DatabaseNames.ToJoinedString(",")}"); IDistributedLock distributedLock = await lockManager.LockAsync( resources : database.DatabaseNames, expiryTime : TimeSpan.FromMinutes(5), waitTime : TimeSpan.FromMinutes(10)).ConfigureAwait(false); try { if (!distributedLock.IsAcquired) { ThrowIfDatabaseInitLockNotGet(database.DatabaseNames); } GlobalSettings.Logger.LogDebug($"获取了初始化数据库的锁:{database.DatabaseNames.ToJoinedString(",")}"); await database.InitializeAsync(migrations).ConfigureAwait(false); } finally { await distributedLock.DisposeAsync().ConfigureAwait(false); } }
/// <summary> /// CosumeTaskProcedure /// </summary> private async Task CosumeAsync(CancellationToken cancellationToken) { while (!cancellationToken.IsCancellationRequested) { try { long now = TimeUtil.UtcNowUnixTimeSeconds; //1, Get Entity IDatabase database = await RedisInstanceManager.GetDatabaseAsync(_instanceSetting, _logger).ConfigureAwait(false); RedisValue redisValue = await database.ListRightPopLeftPushAsync(RedisEventBusEngine.QueueName(_eventType), RedisEventBusEngine.HistoryQueueName(_eventType)).ConfigureAwait(false); if (redisValue.IsNullOrEmpty) { _logger.LogTrace("ConsumeTask Sleep, {InstanceName}, {eventType}", _instanceSetting.InstanceName, _eventType); await Task.Delay(_cONSUME_INTERVAL_SECONDS * 1000, cancellationToken).ConfigureAwait(false); continue; } EventMessageEntity?entity = SerializeUtil.FromJson <EventMessageEntity>(redisValue); if (entity == null) { _logger.LogCritical("有空EventMessageEntity, {eventType}, {value}", _eventType, redisValue); continue; } using IDistributedLock distributedLock = await _lockManager.NoWaitLockAsync( "eBusC_" + entity.Guid, TimeSpan.FromSeconds(_options.EventBusConsumerAckTimeoutSeconds), false, cancellationToken).ConfigureAwait(false); if (!distributedLock.IsAcquired) { //竟然有人在检查entity.Guid,好了,这下肯定有人在处理了,任务结束。哪怕那个人没处理成功,也没事,等着history吧。 continue; } //2, 过期检查 if (now - entity.Timestamp > _eventBusEventMessageExpiredSeconds) { _logger.LogCritical("有EventMessage过期,{eventType}, {entity}", _eventType, SerializeUtil.ToJson(entity)); await distributedLock.DisposeAsync().ConfigureAwait(false); continue; } //3, 防重检查 string AcksSetName = RedisEventBusEngine.AcksSetName(_eventType); bool?isExist = await IsAcksExistedAsync(database, AcksSetName, entity.Guid).ConfigureAwait(false); if (isExist == null || isExist.Value) { _logger.LogInformation("有EventMessage重复,{eventType}, {entity}", _eventType, SerializeUtil.ToJson(entity)); await distributedLock.DisposeAsync().ConfigureAwait(false); continue; } //4, Handle Entity try { await _eventHandler.HandleAsync(entity.JsonData, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { _logger.LogCritical(ex, "处理消息出错, {_eventType}, {entity}", _eventType, SerializeUtil.ToJson(entity)); } //5, Acks await AddAcksAsync(now, database, AcksSetName, entity.Guid, entity.Timestamp).ConfigureAwait(false); _logger.LogTrace("Consume Task For {eventType} Stopped.", _eventType); } catch (RedisConnectionException ex) { _logger.LogError(ex, "Consume 中出现Redis链接问题. {eventType}", _eventType); await Task.Delay(5000, cancellationToken).ConfigureAwait(false); } catch (RedisTimeoutException ex) { _logger.LogError(ex, "Consume 中出现Redis超时问题. {eventType}", _eventType); } catch (Exception ex) { _logger.LogCritical(ex, "Consume 出现未知问题. {eventType}", _eventType); } } }