Skip to content

Commit 9979337

Browse files
erdtsieckjeremydmiller
authored andcommitted
JasperFx#2943 Do not fail aggregate code generation on parallel execution
1 parent 1290ac5 commit 9979337

File tree

2 files changed

+75
-18
lines changed

2 files changed

+75
-18
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
using System.Linq;
2+
using System.Threading.Tasks;
3+
using EventSourcingTests.Projections.CodeGeneration;
4+
using JasperFx.CodeGeneration;
5+
using JasperFx.Core.Reflection;
6+
using Marten;
7+
using Marten.Events.Aggregation;
8+
using Marten.Events.Projections;
9+
using Marten.Internal.CodeGeneration;
10+
using Shouldly;
11+
using Xunit;
12+
13+
namespace EventSourcingTests.Bugs;
14+
15+
public class Bug_2943_generate_aggregate_generated_code_in_parallel
16+
{
17+
[Fact]
18+
public void aggregates_do_not_fail_code_generation_on_parallel_execution()
19+
{
20+
var options = new StoreOptions();
21+
options.Connection("Dummy");
22+
23+
// Given
24+
options.Projections.LiveStreamAggregation<ProjectionCodeGenerationTests.Something>();
25+
26+
// When
27+
var store = new DocumentStore(options);
28+
Parallel.For(1, 100, _ =>
29+
{
30+
Parallel.ForEach(store.Events.As<ICodeFileCollection>().BuildFiles().OfType<IProjectionSource>(), projection =>
31+
{
32+
projection.Build(store);
33+
});
34+
});
35+
36+
// Then
37+
store.Events.As<ICodeFileCollection>().BuildFiles()
38+
.OfType<SingleStreamProjection<ProjectionCodeGenerationTests.Something>>()
39+
.ShouldHaveSingleItem();
40+
41+
options.BuildFiles()
42+
.OfType<DocumentProviderBuilder>()
43+
.Where(e => e.ProviderName == typeof(ProjectionCodeGenerationTests.Something).ToSuffixedTypeName("Provider"))
44+
.ShouldHaveSingleItem();
45+
}
46+
}

src/Marten/Events/Projections/GeneratedProjection.cs

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#nullable enable
22
using System;
33
using System.Collections.Generic;
4-
using System.Diagnostics;
54
using System.Reflection;
65
using System.Threading;
76
using System.Threading.Tasks;
@@ -37,11 +36,14 @@ bool ICodeFile.AttachTypesSynchronously(GenerationRules rules, Assembly assembly
3736

3837
void ICodeFile.AssembleTypes(GeneratedAssembly assembly)
3938
{
40-
if (!_hasGenerated)
39+
lock (_assembleLocker)
4140
{
41+
if (_hasGenerated)
42+
return;
4243
lock (_assembleLocker)
4344
{
44-
if (_hasGenerated) return;
45+
if (_hasGenerated)
46+
return;
4547
assembleTypes(assembly, StoreOptions);
4648
_hasGenerated = true;
4749
}
@@ -95,29 +97,38 @@ ValueTask<EventRangeGroup> IProjectionSource.GroupEvents(DocumentStore store,
9597

9698
private void generateIfNecessary(DocumentStore store)
9799
{
98-
if (_hasGenerated)
100+
lock (_assembleLocker)
99101
{
100-
return;
102+
if (_hasGenerated)
103+
{
104+
return;
105+
}
106+
107+
generateIfNecessaryLocked();
108+
109+
_hasGenerated = true;
101110
}
102111

103-
StoreOptions = store.Options;
104-
var rules = store.Options.CreateGenerationRules();
105-
rules.ReferenceTypes(GetType());
106-
this.As<ICodeFile>().InitializeSynchronously(rules, store.Options.EventGraph, null);
112+
return;
107113

108-
if (needsSettersGenerated())
114+
void generateIfNecessaryLocked()
109115
{
110-
lock (_assembleLocker)
111-
{
112-
var generatedAssembly = new GeneratedAssembly(rules);
113-
assembleTypes(generatedAssembly, store.Options);
116+
StoreOptions = store.Options;
117+
var rules = store.Options.CreateGenerationRules();
118+
rules.ReferenceTypes(GetType());
119+
this.As<ICodeFile>().InitializeSynchronously(rules, store.Options.EventGraph, null);
114120

115-
// This will force it to create any setters or dynamic funcs
116-
generatedAssembly.GenerateCode();
121+
if (!needsSettersGenerated())
122+
{
123+
return;
117124
}
118-
}
119125

120-
_hasGenerated = true;
126+
var generatedAssembly = new GeneratedAssembly(rules);
127+
assembleTypes(generatedAssembly, store.Options);
128+
129+
// This will force it to create any setters or dynamic funcs
130+
generatedAssembly.GenerateCode();
131+
}
121132
}
122133

123134
/// <summary>

0 commit comments

Comments
 (0)