私はDDDを使用しようとしているプロジェクトの終わりに近づいていますが、簡単に解決する方法がわからない眩しいバグを発見しました。エンティティメソッドをリファクタリングして同時実行の問題を回避する
は、ここに私の実体である - 私は簡単にするためにそれを縮小しました:
public class Contribution : Entity
{
protected Contribution()
{
this.Parts = new List<ContributionPart>();
}
internal Contribution(Guid id)
{
this.Id = id;
this.Parts = new List<ContributionPart>();
}
public Guid Id { get; private set; }
protected virtual IList<ContributionPart> Parts { get; private set; }
public void UploadParts(string path, IEnumerable<long> partLengths)
{
if (this.Parts.Count > 0)
{
throw new InvalidOperationException("Parts have already been uploaded.");
}
long startPosition = 0;
int partNumber = 1;
foreach (long partLength in partLengths)
{
this.Parts.Add(new ContributionPart(this.Id, partNumber, partLength));
this.Commands.Add(new UploadContributionPartCommand(this.Id, partNumber, path, startPosition, partLength));
startPosition += partLength;
partNumber++;
}
}
public void SetUploadResult(int partNumber, string etag)
{
if (etag == null)
{
throw new ArgumentNullException(nameof(etag));
}
ContributionPart part = this.Parts.SingleOrDefault(p => p.PartNumber == partNumber);
if (part == null)
{
throw new ContributionPartNotFoundException(this.Id, partNumber);
}
part.SetUploadResult(etag);
if (this.Parts.All(p => p.IsUploaded))
{
IEnumerable<PartUploadedResult> results = this.Parts.Select(p => new PartUploadedResult(p.PartNumber, p.ETag));
this.Events.Add(new ContributionUploaded(this.Id, results));
}
}
}
私のバグがSetUploadResult方法で発生します。基本的に、複数のスレッドが同時にアップロードを実行していて、アップロードの最後にSetUploadResultを呼び出します。しかし、エンティティが数秒前にロードされているため、各スレッドはエンティティの別のインスタンスでSetUploadResultを呼び出しているため、if (this.Parts.All(p => p.IsUploaded)
というテストは決してtrueに評価されません。
これを簡単に解決する方法がわかりません。複数のUploadContributionPartCommandsをCommandsコレクションに追加するという考えは、各ContributionPartを並行してアップロードできるようにすることでした.CommandBusはこれを保証しますが、各パートを並行してアップロードするとエンティティロジックに問題が発生します。
したがって、Contributionエンティティの同じインスタンスで複数のスレッドが動作しているとしますか? – mm8
修正。コントリビューションエンティティは、各partLengthに対してUploadContributionPartCommandを作成し、各UploadContributionPartCommandHandlerはパラレルで実行され、そのため、SetUploadResultを並列に呼び出します。エンティティのインメモリインスタンスと同じではありませんが、同じエンティティです。 –
それぞれのインスタンスには独自の部分があるので、どのように同じ「メモリ内インスタンス」ではないのですか? – mm8