private async Task <(StateMachineEntity, StateMachineInstanceEntity)> PutTestInstance() { var putDto = await PutSimpleDataSet(); var stateMachineRepository = new DummyRepository <StateMachineEntity, Guid>(_storage); var stateMachineInstanceRepository = new DummyRepository <StateMachineInstanceEntity, Guid>(_storage); var stateMachineEntity = await stateMachineRepository.QueryNoTrackingAsync(q => q.FirstOrDefaultAsyncTestable(x => x.Name == putDto.Name)); var stateMachineInstanceEntity = new StateMachineInstanceEntity() { Id = PrimaryKeyUtils.Generate <Guid>(), Name = putDto.Name, Status = StateMachineStatus.Running, Stage = StateMachineBase.InitialStage, InitialBlobs = putDto.InitialBlobs, Limitation = _configuration.Limitation, Parameters = new Dictionary <string, string>() { { "Host", "http://localhost:8888" } }, Priority = 123, FromManagementService = _configuration.Name, ExecutionKey = PrimaryKeyUtils.Generate <Guid>().ToString(), StartTime = DateTime.UtcNow }; await stateMachineInstanceRepository.AddAsync(stateMachineInstanceEntity); await stateMachineInstanceRepository.SaveChangesAsync(); return(stateMachineEntity, stateMachineInstanceEntity); }
public void Generate() { Assert.Equal(0, PrimaryKeyUtils.Generate <int>()); Assert.Equal(0, PrimaryKeyUtils.Generate <long>()); Assert.True(PrimaryKeyUtils.Generate <Guid>() != Guid.Empty); Assert.True(PrimaryKeyUtils.Generate <Guid>() != PrimaryKeyUtils.Generate <Guid>()); }
public void FindSingleBlob() { var blobInfoA = new BlobInfo(PrimaryKeyUtils.Generate <Guid>(), "a.txt"); var blobInfoB = new BlobInfo(PrimaryKeyUtils.Generate <Guid>(), "b.txt"); var blobs = new[] { blobInfoA, blobInfoB }; Assert.True(blobInfoA == blobs.FindSingleBlob("a.txt")); Assert.True(blobInfoB == blobs.FindSingleBlob("b.txt")); Assert.Throws <KeyNotFoundException>(() => blobs.FindSingleBlob("c.txt")); }
public void FindBlob() { var blobInfoA = new BlobInfo(PrimaryKeyUtils.Generate <Guid>(), "a.txt"); var blobInfoB = new BlobInfo(PrimaryKeyUtils.Generate <Guid>(), "b.txt"); var blobs = new[] { blobInfoA, blobInfoB }; Assert.True(blobInfoA == blobs.FindBlob("a.txt")); Assert.True(blobInfoB == blobs.FindBlob("b.txt")); Assert.True(null == blobs.FindBlob("c.txt")); }
public async Task <StateMachineInstancePutResultDto> Put(StateMachineInstancePutDto dto) { // 获取name对应的状态机代码 var stateMachineEntity = await _stateMachineRepository.QueryNoTrackingAsync(q => q.FirstOrDefaultAsyncTestable(x => x.Name == dto.Name)); if (stateMachineEntity == null) { return(StateMachineInstancePutResultDto.NotFound("state machine not found")); } // 创建状态机实例 var stateMachineInstanceEntity = new StateMachineInstanceEntity() { Id = PrimaryKeyUtils.Generate <Guid>(), Name = stateMachineEntity.Name, Status = StateMachineStatus.Running, Stage = StateMachineBase.InitialStage, StartedActors = new List <ActorInfo>(), InitialBlobs = dto.InitialBlobs ?? new BlobInfo[0], Limitation = ContainerLimitation.Default .WithDefaults(dto.Limitation) .WithDefaults(stateMachineEntity.Limitation) .WithDefaults(_configuration.Limitation), Parameters = dto.Parameters, Priority = dto.Priority, FromManagementService = _configuration.Name, ReRunTimes = 0, Exception = null, ExecutionKey = PrimaryKeyUtils.Generate <Guid>().ToString(), StartTime = DateTime.UtcNow, EndTime = null }; var stateMachineInstance = await _stateMachineInstanceStore.CreateInstance( stateMachineEntity, stateMachineInstanceEntity); // 添加状态机实例到数据库 await _repository.AddAsync(stateMachineInstanceEntity); await _repository.SaveChangesAsync(); // 运行状态机, 从这里开始会在后台运行 #pragma warning disable CS4014 _stateMachineInstanceStore.RunInstance(stateMachineInstance); #pragma warning restore CS4014 return(StateMachineInstancePutResultDto.Success( Mapper.Map <StateMachineInstanceEntity, StateMachineInstanceOutputDto>(stateMachineInstanceEntity))); }
public void FindSingleOutputBlob() { var blobInfoA = new BlobInfo(PrimaryKeyUtils.Generate <Guid>(), "a.txt"); var blobInfoB = new BlobInfo(PrimaryKeyUtils.Generate <Guid>(), "b.txt"); var actorInfo = new ActorInfo() { Outputs = new[] { blobInfoA, blobInfoB } }; Assert.True(blobInfoA == actorInfo.FindSingleOutputBlob("a.txt")); Assert.True(blobInfoB == actorInfo.FindSingleOutputBlob("b.txt")); Assert.Throws <KeyNotFoundException>(() => actorInfo.FindSingleOutputBlob("c.txt")); }
public void FindOutputBlob() { var blobInfoA = new BlobInfo(PrimaryKeyUtils.Generate <Guid>(), "a.txt"); var blobInfoB = new BlobInfo(PrimaryKeyUtils.Generate <Guid>(), "b.txt"); var actorInfo = new ActorInfo() { Outputs = new[] { blobInfoA, blobInfoB } }; Assert.True(blobInfoA == actorInfo.FindOutputBlob("a.txt")); Assert.True(blobInfoB == actorInfo.FindOutputBlob("b.txt")); Assert.True(null == actorInfo.FindOutputBlob("c.txt")); }
public async Task <Guid> Put(BlobInputDto dto) { // 获取提交过来的内容, 计算校验值 var originalBytes = Mapper.Map <string, byte[]>(dto.Body); if (dto.IsCompressed) { originalBytes = ArchiveUtils.DecompressFromGZip(originalBytes); } var hash = HashUtils.GetSHA256Hash(originalBytes); using (var transaction = await _repository.BeginTransactionAsync()) { // 如果有相同校验值的blob, 返回该blob var existBlobId = await _repository.QueryNoTrackingAsync(q => q.Where(x => x.BodyHash == hash) .Select(x => x.BlobId) .FirstOrDefaultAsyncTestable()); if (existBlobId != Guid.Empty) { return(existBlobId); } } // 对内容进行分块 var blobId = PrimaryKeyUtils.Generate <Guid>(); var chunks = SplitChunks(blobId, originalBytes, hash, dto.Remark, dto.TimeStamp); // 添加新的blob // 注意并发添加时可能会添加相同内容的blob using (var transaction = await _repository.BeginTransactionAsync()) { foreach (var chunk in chunks) { // 这里需要逐个分块提交, 否则会触发mysql的max_allowed_packet错误 await _repository.AddAsync(chunk); await _repository.SaveChangesAsync(); } transaction.Commit(); } return(blobId); }
public async Task <TPrimaryKey> Put(TInputDto dto) { var entity = new TEntity(); entity.Id = PrimaryKeyUtils.Generate <TPrimaryKey>(); Mapper.Map <TInputDto, TEntity>(dto, entity); if (entity is IEntityWithCreateTime createTimeEntity) { createTimeEntity.CreateTime = DateTime.UtcNow; } if (entity is IEntityWithUpdateTime updateTimeEntity) { updateTimeEntity.UpdateTime = DateTime.UtcNow; } await _repository.AddAsync(entity); await _repository.SaveChangesAsync(); return(entity.Id); }
public async Task SetInstanceStage_ObsoleteExecutionKey() { var(stateMachineEntity, stateMachineInstanceEntity) = await PutTestInstance(); var instance = await _store.CreateInstance(stateMachineEntity, stateMachineInstanceEntity); var repository = new DummyRepository <StateMachineInstanceEntity, Guid>(_storage); stateMachineInstanceEntity.ExecutionKey = PrimaryKeyUtils.Generate <Guid>().ToString(); repository.Update(stateMachineInstanceEntity); await repository.SaveChangesAsync(); await Assert.ThrowsAsync <StateMachineInterpretedException>( () => _store.SetInstanceStage(instance, StateMachineBase.FinalStage)); repository.Remove(stateMachineInstanceEntity); await repository.SaveChangesAsync(); await Assert.ThrowsAsync <StateMachineInterpretedException>( () => _store.SetInstanceStage(instance, StateMachineBase.FinalStage)); }
public IEnumerable <BlobEntity> SplitChunks( Guid blobId, byte[] originalBytes, string hash, string remark, long timeStamp) { // 压缩分块之前的内容 var bodyBytes = ArchiveUtils.CompressToGZip(originalBytes); var chunkIndex = 0; var bodyBytesStart = 0; // 对内容进行分块 do { var entityBodySize = Math.Min(bodyBytes.Length - bodyBytesStart, BlobEntity.BlobChunkSize); var entity = new BlobEntity(); entity.Id = PrimaryKeyUtils.Generate <Guid>(); entity.BlobId = blobId; entity.ChunkIndex = chunkIndex++; entity.Remark = remark; if (bodyBytesStart == 0 && entityBodySize == bodyBytes.Length) { // 不需要分块 entity.Body = bodyBytes; } else { entity.Body = new byte[entityBodySize]; Array.Copy(bodyBytes, bodyBytesStart, entity.Body, 0, entityBodySize); } bodyBytesStart += entityBodySize; entity.TimeStamp = timeStamp == 0 ? DateTime.UtcNow : Mapper.Map <long, DateTime>(timeStamp); entity.BodyHash = hash; entity.CreateTime = DateTime.UtcNow; yield return(entity); } while (bodyBytesStart < bodyBytes.Length); }
public async Task <StateMachineInstancePatchResultDto> Patch(Guid id, StateMachineInstancePatchDto dto) { // 更新阶段, 参数和并发键 StateMachineInstanceEntity stateMachineInstanceEntity = null; StateMachineEntity stateMachineEntity = null; for (int from = 0; from <= ConcurrencyErrorMaxRetryTimes; ++from) { stateMachineInstanceEntity = await _repository.QueryAsync(q => q.FirstOrDefaultAsyncTestable(x => x.Id == id)); if (stateMachineInstanceEntity == null) { return(StateMachineInstancePatchResultDto.NotFound("state machine instance not found")); } stateMachineEntity = await _stateMachineRepository.QueryNoTrackingAsync(q => q.FirstOrDefaultAsyncTestable(x => x.Name == stateMachineInstanceEntity.Name)); if (stateMachineEntity == null) { return(StateMachineInstancePatchResultDto.NotFound("state machine not found")); } stateMachineInstanceEntity.Status = StateMachineStatus.Running; stateMachineInstanceEntity.Stage = dto.Stage ?? StateMachineBase.InitialStage; stateMachineInstanceEntity.ExecutionKey = PrimaryKeyUtils.Generate <Guid>().ToString(); stateMachineInstanceEntity.FromManagementService = _configuration.Name; stateMachineInstanceEntity.StartTime = DateTime.UtcNow; // 柚子大姐要求 if (dto.Parameters != null) { var parameters = stateMachineInstanceEntity.Parameters; foreach (var pair in dto.Parameters) { parameters[pair.Key] = pair.Value; } stateMachineInstanceEntity.Parameters = parameters; } try { await _repository.SaveChangesAsync(); break; } catch (DbUpdateConcurrencyException) { if (from == ConcurrencyErrorMaxRetryTimes) { throw; } await Task.Delay(1); } } // 创建状态机实例 var stateMachineInstance = await _stateMachineInstanceStore.CreateInstance( stateMachineEntity, stateMachineInstanceEntity); // 运行状态机, 从这里开始会在后台运行 #pragma warning disable CS4014 _stateMachineInstanceStore.RunInstance(stateMachineInstance); #pragma warning restore CS4014 return(StateMachineInstancePatchResultDto.Success()); }