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"));
        }
Пример #8
0
        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));
        }
Пример #11
0
        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());
        }