Skip to content

Commit 6f9e8ec

Browse files
authored
Merge pull request #321 from neuroglia-io/fix-persistence-issues
Fixed Neuroglia package reference, thus fixing a critical EventStore bug related to snapshot serialization
2 parents 1c92db0 + 5ca3f3b commit 6f9e8ec

File tree

17 files changed

+254
-187
lines changed

17 files changed

+254
-187
lines changed

src/apis/management/Synapse.Apis.Management.Grpc.Client/Synapse.Apis.Management.Grpc.Client.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
<ProjectReference Include="..\Synapse.Apis.Management.Core\Synapse.Apis.Management.Core.csproj" />
3636
</ItemGroup>
3737
<ItemGroup>
38-
<PackageReference Include="protobuf-net.Grpc" Version="1.0.177" />
39-
<PackageReference Include="protobuf-net.Grpc.ClientFactory" Version="1.0.177" />
38+
<PackageReference Include="protobuf-net.Grpc" Version="1.0.179" />
39+
<PackageReference Include="protobuf-net.Grpc.ClientFactory" Version="1.0.179" />
4040
</ItemGroup>
4141
</Project>

src/apis/management/Synapse.Apis.Management.Http/Synapse.Apis.Management.Http.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.10" />
2929
<PackageReference Include="Microsoft.AspNetCore.OData" Version="8.0.11" />
3030
<PackageReference Include="Microsoft.AspNetCore.OData.NewtonsoftJson" Version="8.0.4" />
31-
<PackageReference Include="Neuroglia.Mediation.AspNetCore" Version="2.0.7" />
31+
<PackageReference Include="Neuroglia.Mediation.AspNetCore" Version="2.0.9" />
3232
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.4.0" />
3333
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="6.4.0" />
3434
</ItemGroup>

src/apis/runtime/Synapse.Apis.Runtime.Grpc.Client/Synapse.Apis.Runtime.Grpc.Client.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@
3232
</None>
3333
</ItemGroup>
3434
<ItemGroup>
35-
<PackageReference Include="protobuf-net.Grpc" Version="1.0.177" />
36-
<PackageReference Include="protobuf-net.Grpc.ClientFactory" Version="1.0.177" />
35+
<PackageReference Include="protobuf-net.Grpc" Version="1.0.179" />
36+
<PackageReference Include="protobuf-net.Grpc.ClientFactory" Version="1.0.179" />
3737
</ItemGroup>
3838
<ItemGroup>
3939
<ProjectReference Include="..\Synapse.Apis.Runtime.Core\Synapse.Apis.Runtime.Core.csproj" />

src/apps/Synapse.Server/Synapse.Server.csproj

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@
3232
<ItemGroup>
3333
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="6.0.10" />
3434
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.17.0" />
35-
<PackageReference Include="Neuroglia.Caching.InMemory" Version="2.0.7" />
36-
<PackageReference Include="Neuroglia.Data.Expressions.JQ" Version="2.0.7" />
37-
<PackageReference Include="Neuroglia.Eventing.CloudEvents.AspNetCore" Version="2.0.7" />
38-
<PackageReference Include="Neuroglia.Serialization.Json" Version="2.0.7" />
39-
<PackageReference Include="protobuf-net.Grpc.AspNetCore" Version="1.0.177" />
35+
<PackageReference Include="Neuroglia.Caching.InMemory" Version="2.0.9" />
36+
<PackageReference Include="Neuroglia.Data.Expressions.JQ" Version="2.0.9" />
37+
<PackageReference Include="Neuroglia.Eventing.CloudEvents.AspNetCore" Version="2.0.9" />
38+
<PackageReference Include="Neuroglia.Serialization.Json" Version="2.0.9" />
39+
<PackageReference Include="protobuf-net.Grpc.AspNetCore" Version="1.0.179" />
4040
<PackageReference Include="System.IO.FileSystem" Version="4.3.0" />
4141
</ItemGroup>
4242
<ItemGroup>

src/apps/Synapse.Server/appsettings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
},
1515
"CloudEvents": {
1616
"Sink": {
17-
"Uri": "https://en37uhd2he6t4.x.pipedream.net"
17+
"Uri": "https://webhook.site/0d0f64a9-fc21-49bb-a2a9-e230929dcc0f"
1818
}
1919
}
2020
}

src/apps/Synapse.Worker/Synapse.Worker.csproj

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,12 @@
4040
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
4141
</PackageReference>
4242
<PackageReference Include="Neuroglia.AsyncApi.Client.All" Version="2.1.0.6" />
43-
<PackageReference Include="Neuroglia.Data.Expressions.JQ" Version="2.0.7" />
44-
<PackageReference Include="Neuroglia.Eventing.CloudEvents" Version="2.0.7" />
45-
<PackageReference Include="Neuroglia.Serialization.NewtonsoftJson" Version="2.0.7" />
46-
<PackageReference Include="protobuf-net.Grpc" Version="1.0.177" />
47-
<PackageReference Include="protobuf-net.Grpc.ClientFactory" Version="1.0.177" />
48-
<PackageReference Include="Simple.OData.Client" Version="5.26.0" />
43+
<PackageReference Include="Neuroglia.Data.Expressions.JQ" Version="2.0.9" />
44+
<PackageReference Include="Neuroglia.Eventing.CloudEvents" Version="2.0.9" />
45+
<PackageReference Include="Neuroglia.Serialization.NewtonsoftJson" Version="2.0.9" />
46+
<PackageReference Include="protobuf-net.Grpc" Version="1.0.179" />
47+
<PackageReference Include="protobuf-net.Grpc.ClientFactory" Version="1.0.179" />
48+
<PackageReference Include="Simple.OData.Client" Version="6.0.1" />
4949
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
5050
</ItemGroup>
5151
<ItemGroup>

src/core/Synapse.Application/Services/PluginBasedRepositoryFactory.cs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,21 @@
1-
using Synapse.Infrastructure;
1+
/*
2+
* Copyright © 2022-Present The Synapse Authors
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* <p>
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
* <p>
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
18+
using Synapse.Infrastructure;
219
using Synapse.Infrastructure.Plugins;
320

421
namespace Synapse.Application.Services

src/core/Synapse.Application/Services/WorkflowDefinitionFileMonitor.cs

Lines changed: 140 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -18,140 +18,148 @@
1818
using ServerlessWorkflow.Sdk.Models;
1919
using ServerlessWorkflow.Sdk.Services.IO;
2020
using Synapse.Application.Commands.Workflows;
21-
22-
namespace Synapse.Application.Services
21+
using Synapse.Infrastructure.Plugins;
22+
23+
namespace Synapse.Application.Services;
24+
25+
26+
/// <summary>
27+
/// Represents an <see cref="IHostedService"/> used to monitor <see cref="WorkflowDefinition"/> files
28+
/// </summary>
29+
public class WorkflowDefinitionFileMonitor
30+
: BackgroundService
31+
{
32+
33+
/// <summary>
34+
/// Initializes a new <see cref="WorkflowDefinitionFileMonitor"/>
35+
/// </summary>
36+
/// <param name="serviceProvider">The current <see cref="IServiceProvider"/></param>
37+
/// <param name="logger">The service used to perform logging</param>
38+
/// <param name="options">The service used to access the current <see cref="SynapseApplicationOptions"/></param>
39+
/// <param name="pluginManager">The service used to manage <see cref="IPlugin"/>s</param>
40+
/// <param name="workflowReader">The service used to read <see cref="WorkflowDefinition"/>s</param>
41+
public WorkflowDefinitionFileMonitor(IServiceProvider serviceProvider, ILogger<WorkflowDefinitionFileMonitor> logger, IOptions<SynapseApplicationOptions> options, IPluginManager pluginManager, IWorkflowReader workflowReader)
2342
{
24-
25-
/// <summary>
26-
/// Represents an <see cref="IHostedService"/> used to monitor <see cref="WorkflowDefinition"/> files
27-
/// </summary>
28-
public class WorkflowDefinitionFileMonitor
29-
: BackgroundService
43+
this.ServiceProvider = serviceProvider;
44+
this.Logger = logger;
45+
this.Options = options.Value;
46+
this.PluginManager = pluginManager;
47+
this.WorkflowReader = workflowReader;
48+
}
49+
50+
/// <summary>
51+
/// Gets the current <see cref="IServiceProvider"/>
52+
/// </summary>
53+
protected IServiceProvider ServiceProvider { get; }
54+
55+
/// <summary>
56+
/// Gets the service used to perform logging
57+
/// </summary>
58+
protected ILogger Logger { get; }
59+
60+
/// <summary>
61+
/// Gets the current <see cref="SynapseApplicationOptions"/>
62+
/// </summary>
63+
protected SynapseApplicationOptions Options { get; }
64+
65+
/// <summary>
66+
/// Gets the service used to manage <see cref="IPlugin"/>s
67+
/// </summary>
68+
protected IPluginManager PluginManager { get; }
69+
70+
/// <summary>
71+
/// Gets the service used to read <see cref="WorkflowDefinition"/>s
72+
/// </summary>
73+
protected IWorkflowReader WorkflowReader { get; }
74+
75+
/// <summary>
76+
/// Gets the <see cref="WorkflowDefinitionFileMonitor"/>'s <see cref="System.Threading.CancellationTokenSource"/>
77+
/// </summary>
78+
protected CancellationTokenSource CancellationTokenSource { get; private set; } = null!;
79+
80+
/// <summary>
81+
/// Gets a service used to watch <see cref="WorkflowDefinition"/> files
82+
/// </summary>
83+
protected FileSystemWatcher FileSystemWatcher { get; private set; } = null!;
84+
85+
/// <inheritdoc/>
86+
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
87+
{
88+
await this.PluginManager.WaitForStartupAsync(stoppingToken);
89+
if (string.IsNullOrWhiteSpace(this.Options.DefinitionsDirectory))
90+
return;
91+
this.CancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(stoppingToken);
92+
var directory = new DirectoryInfo(this.Options.DefinitionsDirectory);
93+
if (!directory.Exists)
94+
directory.Create();
95+
this.FileSystemWatcher = new(directory.FullName)
96+
{
97+
IncludeSubdirectories = true,
98+
NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName,
99+
EnableRaisingEvents = true
100+
};
101+
this.FileSystemWatcher.Created += this.OnFileCreatedOrChangedAsync;
102+
this.FileSystemWatcher.Changed += this.OnFileCreatedOrChangedAsync;
103+
foreach (var file in directory.GetFiles("*.*", SearchOption.AllDirectories)
104+
.Where(f => f.Extension.ToLower() == ".json" || f.Extension.ToLower() == ".yml" || f.Extension.ToLower() == ".yaml"))
30105
{
106+
await this.ReadAndCreateWorkflowAsync(file.FullName, true);
107+
}
108+
}
109+
110+
/// <summary>
111+
/// Handles the creation of a new file in the definitions directory
112+
/// </summary>
113+
/// <param name="sender">The sender of the <see cref="FileSystemEventArgs"/></param>
114+
/// <param name="e">The <see cref="FileSystemEventArgs"/> to handle</param>
115+
protected virtual async void OnFileCreatedOrChangedAsync(object sender, FileSystemEventArgs e)
116+
{
117+
if (e.ChangeType != WatcherChangeTypes.Created
118+
&& e.ChangeType != WatcherChangeTypes.Changed)
119+
return;
120+
switch (Path.GetExtension(e.FullPath.ToLower()))
121+
{
122+
case ".json":
123+
case ".yaml":
124+
case ".yml":
125+
break;
126+
default:
127+
return;
128+
}
129+
await this.ReadAndCreateWorkflowAsync(e.FullPath, false);
130+
}
131+
132+
/// <summary>
133+
/// Reads the <see cref="WorkflowDefinition"/> from the specified file and creates a new <see cref="V1Workflow"/>, if it does not already exist
134+
/// </summary>
135+
/// <param name="filePath">The path to the <see cref="WorkflowDefinition"/> file to read</param>
136+
/// <param name="ifNotExists">A boolean indicating to only import read and create a new <see cref="V1Workflow"/> if it already exists</param>
137+
/// <returns>A new awaitable <see cref="Task"/></returns>
138+
protected virtual async Task ReadAndCreateWorkflowAsync(string filePath, bool ifNotExists)
139+
{
140+
try
141+
{
142+
using var stream = File.OpenRead(filePath);
143+
var definition = await this.WorkflowReader.ReadAsync(stream);
144+
using var scope = this.ServiceProvider.CreateScope();
145+
await scope.ServiceProvider.GetRequiredService<IMediator>().ExecuteAndUnwrapAsync(new V1CreateWorkflowCommand(definition, ifNotExists), this.CancellationTokenSource.Token);
146+
}
147+
catch (IOException ex) when (ex.HResult == -2147024864) { }
148+
catch (Exception ex)
149+
{
150+
this.Logger.LogError("An error occured while reading a valid Serverless Workflow definition from the specified file '{filePath}': {ex}", filePath, ex.ToString());
151+
return;
152+
}
153+
}
31154

32-
/// <summary>
33-
/// Initializes a new <see cref="WorkflowDefinitionFileMonitor"/>
34-
/// </summary>
35-
/// <param name="serviceProvider">The current <see cref="IServiceProvider"/></param>
36-
/// <param name="logger">The service used to perform logging</param>
37-
/// <param name="options">The service used to access the current <see cref="SynapseApplicationOptions"/></param>
38-
/// <param name="workflowReader">The service used to read <see cref="WorkflowDefinition"/>s</param>
39-
public WorkflowDefinitionFileMonitor(IServiceProvider serviceProvider, ILogger<WorkflowDefinitionFileMonitor> logger, IOptions<SynapseApplicationOptions> options, IWorkflowReader workflowReader)
40-
{
41-
this.ServiceProvider = serviceProvider;
42-
this.Logger = logger;
43-
this.Options = options.Value;
44-
this.WorkflowReader = workflowReader;
45-
}
46-
47-
/// <summary>
48-
/// Gets the current <see cref="IServiceProvider"/>
49-
/// </summary>
50-
protected IServiceProvider ServiceProvider { get; }
51-
52-
/// <summary>
53-
/// Gets the service used to perform logging
54-
/// </summary>
55-
protected ILogger Logger { get; }
56-
57-
/// <summary>
58-
/// Gets the current <see cref="SynapseApplicationOptions"/>
59-
/// </summary>
60-
protected SynapseApplicationOptions Options { get; }
61-
62-
/// <summary>
63-
/// Gets the service used to read <see cref="WorkflowDefinition"/>s
64-
/// </summary>
65-
protected IWorkflowReader WorkflowReader { get; }
66-
67-
/// <summary>
68-
/// Gets the <see cref="WorkflowDefinitionFileMonitor"/>'s <see cref="System.Threading.CancellationTokenSource"/>
69-
/// </summary>
70-
protected CancellationTokenSource CancellationTokenSource { get; private set; } = null!;
71-
72-
/// <summary>
73-
/// Gets a service used to watch <see cref="WorkflowDefinition"/> files
74-
/// </summary>
75-
protected FileSystemWatcher FileSystemWatcher { get; private set; } = null!;
76-
77-
/// <inheritdoc/>
78-
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
79-
{
80-
if (string.IsNullOrWhiteSpace(this.Options.DefinitionsDirectory))
81-
return;
82-
this.CancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(stoppingToken);
83-
var directory = new DirectoryInfo(this.Options.DefinitionsDirectory);
84-
if (!directory.Exists)
85-
directory.Create();
86-
this.FileSystemWatcher = new(directory.FullName)
87-
{
88-
IncludeSubdirectories = true,
89-
NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName,
90-
EnableRaisingEvents = true
91-
};
92-
this.FileSystemWatcher.Created += this.OnFileCreatedOrChangedAsync;
93-
this.FileSystemWatcher.Changed += this.OnFileCreatedOrChangedAsync;
94-
foreach (var file in directory.GetFiles("*.*", SearchOption.AllDirectories)
95-
.Where(f => f.Extension.ToLower() == ".json" || f.Extension.ToLower() == ".yml" || f.Extension.ToLower() == ".yaml"))
96-
{
97-
await this.ReadAndCreateWorkflowAsync(file.FullName, true);
98-
}
99-
}
100-
101-
/// <summary>
102-
/// Handles the creation of a new file in the definitions directory
103-
/// </summary>
104-
/// <param name="sender">The sender of the <see cref="FileSystemEventArgs"/></param>
105-
/// <param name="e">The <see cref="FileSystemEventArgs"/> to handle</param>
106-
protected virtual async void OnFileCreatedOrChangedAsync(object sender, FileSystemEventArgs e)
107-
{
108-
if (e.ChangeType != WatcherChangeTypes.Created
109-
&& e.ChangeType != WatcherChangeTypes.Changed)
110-
return;
111-
switch (Path.GetExtension(e.FullPath.ToLower()))
112-
{
113-
case ".json":
114-
case ".yaml":
115-
case ".yml":
116-
break;
117-
default:
118-
return;
119-
}
120-
await this.ReadAndCreateWorkflowAsync(e.FullPath, false);
121-
}
122-
123-
/// <summary>
124-
/// Reads the <see cref="WorkflowDefinition"/> from the specified file and creates a new <see cref="V1Workflow"/>, if it does not already exist
125-
/// </summary>
126-
/// <param name="filePath">The path to the <see cref="WorkflowDefinition"/> file to read</param>
127-
/// <param name="ifNotExists">A boolean indicating to only import read and create a new <see cref="V1Workflow"/> if it already exists</param>
128-
/// <returns>A new awaitable <see cref="Task"/></returns>
129-
protected virtual async Task ReadAndCreateWorkflowAsync(string filePath, bool ifNotExists)
130-
{
131-
try
132-
{
133-
using var stream = File.OpenRead(filePath);
134-
var definition = await this.WorkflowReader.ReadAsync(stream);
135-
using var scope = this.ServiceProvider.CreateScope();
136-
await scope.ServiceProvider.GetRequiredService<IMediator>().ExecuteAndUnwrapAsync(new V1CreateWorkflowCommand(definition, ifNotExists), this.CancellationTokenSource.Token);
137-
}
138-
catch (IOException ex) when (ex.HResult == -2147024864) { }
139-
catch (Exception ex)
140-
{
141-
this.Logger.LogError("An error occured while reading a valid Serverless Workflow definition from the specified file '{filePath}': {ex}", filePath, ex.ToString());
142-
return;
143-
}
144-
}
145-
146-
/// <inheritdoc/>
147-
public override void Dispose()
148-
{
149-
this.CancellationTokenSource?.Dispose();
150-
this.FileSystemWatcher?.Dispose();
151-
base.Dispose();
152-
GC.SuppressFinalize(this);
153-
}
155+
/// <inheritdoc/>
156+
public override void Dispose()
157+
{
158+
this.CancellationTokenSource?.Dispose();
159+
this.FileSystemWatcher?.Dispose();
160+
base.Dispose();
161+
GC.SuppressFinalize(this);
162+
}
154163

155-
}
164+
}
156165

157-
}

0 commit comments

Comments
 (0)