Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
6fdc65e
WIP: Fix garnet persistence
Alirexaa Jul 26, 2024
d4508ae
Merge branch 'main' into fix-garnet-persistence
Alirexaa Jul 26, 2024
c9889d3
remove --aof-commit-freq arg
Alirexaa Jul 26, 2024
f06bf89
Merge branch 'fix-garnet-persistence' of https://github.com/Alirexaa/…
Alirexaa Jul 26, 2024
a721a37
Merge branch 'main' into fix-garnet-persistence
Alirexaa Jul 30, 2024
f42201f
fix `WithPersistence`, using new args
Alirexaa Jul 30, 2024
e629c81
revert image tag
Alirexaa Jul 30, 2024
5863341
Merge branch 'dotnet:main' into fix-garnet-persistence
Alirexaa Jul 31, 2024
6474dee
change playground app to new formet
Alirexaa Jul 31, 2024
ed15673
mark method as Obsolete
Alirexaa Jul 31, 2024
489a57b
move shipped api from unshipped to shipped
Alirexaa Aug 1, 2024
c23641d
fix AddGarnetTests and add functional tests
Alirexaa Aug 1, 2024
46bd31a
Add ResourceLoggerForwarderService to builder and increase delay
Alirexaa Aug 1, 2024
3e3dfff
Merge branch 'main' into fix-garnet-persistence
Alirexaa Aug 8, 2024
7d87138
minor change
Alirexaa Aug 8, 2024
545ba30
Merge branch 'dotnet:main' into fix-garnet-persistence
Alirexaa Aug 9, 2024
b1f5d5d
fix test
Alirexaa Aug 9, 2024
9a991eb
Merge branch 'dotnet:main' into fix-garnet-persistence
Alirexaa Aug 9, 2024
e8559ba
Merge branch 'dotnet:main' into fix-garnet-persistence
Alirexaa Aug 10, 2024
a1f4452
Merge branch 'dotnet:main' into fix-garnet-persistence
Alirexaa Aug 12, 2024
36047b7
Remove unnecessary change
eerhardt Aug 12, 2024
741fb24
try fix test
Alirexaa Aug 12, 2024
7abdfbf
Merge branch 'main' into fix-garnet-persistence
Alirexaa Aug 14, 2024
f679c56
Merge branch 'main' into fix-garnet-persistence
Alirexaa Sep 3, 2024
a2a7006
Address PR feedback
Alirexaa Sep 3, 2024
18a3a95
Add playground tests
Alirexaa Sep 3, 2024
2dc8f79
fix build
Alirexaa Sep 3, 2024
10ca7e0
fix playground tests
Alirexaa Sep 3, 2024
9af6c93
Use "other" read/write permissions.
eerhardt Sep 4, 2024
91d8981
Update appsettings.json
Alirexaa Sep 4, 2024
214cdb8
Fix bind mount directory permissions
eerhardt Sep 5, 2024
08ef349
Merge branch 'main' into fix-garnet-persistence
Alirexaa Sep 13, 2024
90b42fe
Merge branch 'dotnet:main' into fix-garnet-persistence
Alirexaa Sep 13, 2024
9eeb9b3
Merge branch 'dotnet:main' into fix-garnet-persistence
Alirexaa Sep 14, 2024
3aaf95d
Merge branch 'dotnet:main' into fix-garnet-persistence
Alirexaa Sep 15, 2024
3adddab
Merge branch 'dotnet:main' into fix-garnet-persistence
Alirexaa Sep 16, 2024
e13427e
Merge branch 'main' into fix-garnet-persistence
Alirexaa Sep 17, 2024
0c4e3a5
Address PR feedback
Alirexaa Sep 17, 2024
8edbd70
Merge branch 'dotnet:main' into fix-garnet-persistence
Alirexaa Sep 17, 2024
ad4bc74
Merge branch 'dotnet:main' into fix-garnet-persistence
Alirexaa Sep 18, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions Aspire.sln
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aspire.Hosting.Keycloak.Tes
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aspire.Keycloak.Authentication.Tests", "tests\Aspire.Keycloak.Authentication.Tests\Aspire.Keycloak.Authentication.Tests.csproj", "{48FF09E9-7D33-4A3F-9FF2-4C43A219C7B7}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Garnet", "Garnet", "{39E23812-12FB-4E49-AA13-499332E49A5A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aspire.Hosting.MongoDB.Tests", "tests\Aspire.Hosting.MongoDB.Tests\Aspire.Hosting.MongoDB.Tests.csproj", "{DD9BC533-8072-481C-9A7E-F95DC36B34C0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aspire.Hosting.Nats.Tests", "tests\Aspire.Hosting.Nats.Tests\Aspire.Hosting.Nats.Tests.csproj", "{F492357C-682E-4CBB-A374-1A124B3976A3}"
Expand Down Expand Up @@ -612,9 +614,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AWSCDK.AppHost", "playgroun
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Redis", "Redis", "{874EA351-05EA-44F5-8B12-7A7F865ECEC5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Redis.ApiService", "playground\Redis\Redis.ApiService\Redis.ApiService.csproj", "{B4CB2D9D-D3F5-4BB1-A7C0-7A6F13316A78}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Redis.ApiService", "playground\Redis\Redis.ApiService\Redis.ApiService.csproj", "{B4CB2D9D-D3F5-4BB1-A7C0-7A6F13316A78}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Redis.AppHost", "playground\Redis\Redis.AppHost\Redis.AppHost.csproj", "{6249A193-3BF4-4FFB-AB81-6590A8318889}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Redis.AppHost", "playground\Redis\Redis.AppHost\Redis.AppHost.csproj", "{6249A193-3BF4-4FFB-AB81-6590A8318889}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -1887,6 +1889,7 @@ Global
{C556D61C-7E11-43EC-9098-C8D170FEA905} = {EBC55A17-B0D6-4E0A-9DC2-7D264E96F631}
{5867BAF2-FEF0-4661-BFDE-9ADCDC2921CD} = {830A89EC-4029-4753-B25A-068BAE37DEC7}
{48FF09E9-7D33-4A3F-9FF2-4C43A219C7B7} = {C424395C-1235-41A4-BF55-07880A04368C}
{39E23812-12FB-4E49-AA13-499332E49A5A} = {D173887B-AF42-4576-B9C1-96B9E9B3D9C0}
{DD9BC533-8072-481C-9A7E-F95DC36B34C0} = {830A89EC-4029-4753-B25A-068BAE37DEC7}
{F492357C-682E-4CBB-A374-1A124B3976A3} = {830A89EC-4029-4753-B25A-068BAE37DEC7}
{D705FE42-CD54-4575-BA18-0431256B40B2} = {830A89EC-4029-4753-B25A-068BAE37DEC7}
Expand Down
23 changes: 20 additions & 3 deletions playground/Redis/Redis.ApiService/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,37 @@

builder.AddServiceDefaults();
builder.AddRedisClient("redis");
builder.AddKeyedRedisClient("garnet");

var app = builder.Build();

app.MapGet("/ping", async (IConnectionMultiplexer connection) =>
app.MapGet("/redis/ping", async (IConnectionMultiplexer connection) =>
{
return await connection.GetDatabase().PingAsync();
});

app.MapGet("/set", async (IConnectionMultiplexer connection) =>
app.MapGet("/redis/set", async (IConnectionMultiplexer connection) =>
{
return await connection.GetDatabase().StringSetAsync("Key", $"{DateTime.Now}");
});

app.MapGet("/get", async (IConnectionMultiplexer connection) =>
app.MapGet("/redis/get", async (IConnectionMultiplexer connection) =>
{
var redisValue = await connection.GetDatabase().StringGetAsync("Key");
return redisValue.HasValue ? redisValue.ToString() : "(null)";
});

app.MapGet("/garnet/ping", async ([FromKeyedServices("garnet")] IConnectionMultiplexer connection) =>
{
return await connection.GetDatabase().PingAsync();
});

app.MapGet("/garnet/set", async ([FromKeyedServices("garnet")] IConnectionMultiplexer connection) =>
{
return await connection.GetDatabase().StringSetAsync("Key", $"{DateTime.Now}");
});

app.MapGet("/garnet/get", async ([FromKeyedServices("garnet")] IConnectionMultiplexer connection) =>
{
var redisValue = await connection.GetDatabase().StringGetAsync("Key");
return redisValue.HasValue ? redisValue.ToString() : "(null)";
Expand Down
7 changes: 5 additions & 2 deletions playground/Redis/Redis.AppHost/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
.WithRedisCommander()
.WithRedisInsight(c => c.WithAcceptEula(true));

var garnet = builder.AddGarnet("garnet")
.WithDataVolume("garnet-data");

builder.AddProject<Projects.Redis_ApiService>("apiservice")
.WithReference(redis)
.WaitFor(redis);
.WithReference(redis).WaitFor(redis)
.WithReference(garnet).WaitFor(garnet);

builder.Build().Run();
1 change: 1 addition & 0 deletions playground/Redis/Redis.AppHost/Redis.AppHost.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<ItemGroup>
<AspireProjectOrPackageReference Include="Aspire.Hosting.AppHost" />
<AspireProjectOrPackageReference Include="Aspire.Hosting.Redis" />
<AspireProjectOrPackageReference Include="Aspire.Hosting.Garnet" />
<ProjectReference Include="..\Redis.ApiService\Redis.ApiService.csproj" />
</ItemGroup>

Expand Down
31 changes: 30 additions & 1 deletion playground/Redis/Redis.AppHost/aspire-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,34 @@
}
}
},
"garnet": {
"type": "container.v0",
"connectionString": "{garnet.bindings.tcp.host}:{garnet.bindings.tcp.port}",
"image": "ghcr.io/microsoft/garnet:1.0",
"args": [
"--checkpointdir",
"/data/checkpoints",
"--recover",
"--aof",
"--aof-commit-freq",
"60000"
],
"volumes": [
{
"name": "garnet-data",
"target": "/data",
"readOnly": false
}
],
"bindings": {
"tcp": {
"scheme": "tcp",
"protocol": "tcp",
"transport": "tcp",
"targetPort": 6379
}
}
},
"apiservice": {
"type": "project.v0",
"path": "../Redis.ApiService/Redis.ApiService.csproj",
Expand All @@ -35,7 +63,8 @@
"OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY": "in_memory",
"ASPNETCORE_FORWARDEDHEADERS_ENABLED": "true",
"HTTP_PORTS": "{apiservice.bindings.http.targetPort}",
"ConnectionStrings__redis": "{redis.connectionString}"
"ConnectionStrings__redis": "{redis.connectionString}",
"ConnectionStrings__garnet": "{garnet.connectionString}"
},
"bindings": {
"http": {
Expand Down
42 changes: 32 additions & 10 deletions src/Aspire.Hosting.Garnet/GarnetBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,11 @@ public static IResourceBuilder<GarnetResource> AddGarnet(this IDistributedApplic
/// Adds a named volume for the data folder to a Garnet container resource and enables Garnet persistence.
/// </summary>
/// <example>
/// Use <see cref="WithPersistence(IResourceBuilder{GarnetResource}, TimeSpan?, long)"/> to adjust Garnet persistence configuration, e.g.:
/// Use <see cref="WithPersistence(IResourceBuilder{GarnetResource}, TimeSpan?)"/> to adjust Garnet persistence configuration, e.g.:
/// <code lang="csharp">
/// var cache = builder.AddGarnet("cache")
/// .WithDataVolume()
/// .WithPersistence(TimeSpan.FromSeconds(10), 5);
/// .WithPersistence(TimeSpan.FromSeconds(10));
/// </code>
/// </example>
/// <param name="builder">The resource builder.</param>
Expand Down Expand Up @@ -116,11 +116,11 @@ public static IResourceBuilder<GarnetResource> WithDataVolume(this IResourceBuil
/// Adds a bind mount for the data folder to a Garnet container resource and enables Garnet persistence.
/// </summary>
/// <example>
/// Use <see cref="WithPersistence(IResourceBuilder{GarnetResource}, TimeSpan?, long)"/> to adjust Garnet persistence configuration, e.g.:
/// Use <see cref="WithPersistence(IResourceBuilder{GarnetResource}, TimeSpan?)"/> to adjust Garnet persistence configuration, e.g.:
/// <code lang="csharp">
/// var garnet = builder.AddGarnet("garnet")
/// .WithDataBindMount("mydata")
/// .WithPersistence(TimeSpan.FromSeconds(10), 5);
/// .WithPersistence(TimeSpan.FromSeconds(10));
/// </code>
/// </example>
/// <param name="builder">The resource builder.</param>
Expand Down Expand Up @@ -154,24 +154,46 @@ public static IResourceBuilder<GarnetResource> WithDataBindMount(this IResourceB
/// <code lang="csharp">
/// var cache = builder.AddGarnet("cache")
/// .WithDataVolume()
/// .WithPersistence(TimeSpan.FromSeconds(10), 5);
/// .WithPersistence(TimeSpan.FromSeconds(10));
/// </code>
/// </example>
/// <param name="builder">The resource builder.</param>
/// <param name="interval">The interval between snapshot exports. Defaults to 60 seconds.</param>
/// <param name="keysChangedThreshold">The number of key change operations required to trigger a snapshot at the interval. Defaults to 1.</param>
/// <returns>The <see cref="IResourceBuilder{T}"/>.</returns>
[Obsolete("This method is obsolete and will be removed in a future version. Use the overload without the keysChangedThreshold parameter.")]
public static IResourceBuilder<GarnetResource> WithPersistence(this IResourceBuilder<GarnetResource> builder,
TimeSpan? interval = null, long keysChangedThreshold = 1)
TimeSpan? interval, long keysChangedThreshold)
=> WithPersistence(builder, interval);

/// <summary>
/// Configures a Garnet container resource for persistence.
/// </summary>
/// <example>
/// Use with <see cref="WithDataBindMount(IResourceBuilder{GarnetResource}, string, bool)"/>
/// or <see cref="WithDataVolume(IResourceBuilder{GarnetResource}, string?, bool)"/> to persist Garnet data across sessions with custom persistence configuration, e.g.:
/// <code lang="csharp">
/// var cache = builder.AddGarnet("cache")
/// .WithDataVolume()
/// .WithPersistence(TimeSpan.FromSeconds(10));
/// </code>
/// </example>
/// <param name="builder">The resource builder.</param>
/// <param name="interval">The interval between snapshot exports. Defaults to 60 seconds.</param>
/// <returns>The <see cref="IResourceBuilder{T}"/>.</returns>
public static IResourceBuilder<GarnetResource> WithPersistence(this IResourceBuilder<GarnetResource> builder,
TimeSpan? interval = null)
{
ArgumentNullException.ThrowIfNull(builder);

return builder.WithAnnotation(new CommandLineArgsCallbackAnnotation(context =>
{
context.Args.Add("--save");
context.Args.Add(
(interval ?? TimeSpan.FromSeconds(60)).TotalSeconds.ToString(CultureInfo.InvariantCulture));
context.Args.Add(keysChangedThreshold.ToString(CultureInfo.InvariantCulture));
context.Args.Add("--checkpointdir");
context.Args.Add("/data/checkpoints");
context.Args.Add("--recover");
context.Args.Add("--aof");
context.Args.Add("--aof-commit-freq");
context.Args.Add((interval ?? TimeSpan.FromSeconds(60)).TotalMilliseconds.ToString(CultureInfo.InvariantCulture));
return Task.CompletedTask;
}), ResourceAnnotationMutationBehavior.Replace);
}
Expand Down
9 changes: 9 additions & 0 deletions src/Aspire.Hosting.Garnet/PublicAPI.Shipped.txt
Original file line number Diff line number Diff line change
@@ -1 +1,10 @@
#nullable enable
Aspire.Hosting.ApplicationModel.GarnetResource
Aspire.Hosting.ApplicationModel.GarnetResource.ConnectionStringExpression.get -> Aspire.Hosting.ApplicationModel.ReferenceExpression!
Aspire.Hosting.ApplicationModel.GarnetResource.PrimaryEndpoint.get -> Aspire.Hosting.ApplicationModel.EndpointReference!
Aspire.Hosting.ApplicationModel.GarnetResource.GarnetResource(string! name) -> void
Aspire.Hosting.GarnetBuilderExtensions
static Aspire.Hosting.GarnetBuilderExtensions.AddGarnet(this Aspire.Hosting.IDistributedApplicationBuilder! builder, string! name, int? port = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder<Aspire.Hosting.ApplicationModel.GarnetResource!>!
static Aspire.Hosting.GarnetBuilderExtensions.WithDataBindMount(this Aspire.Hosting.ApplicationModel.IResourceBuilder<Aspire.Hosting.ApplicationModel.GarnetResource!>! builder, string! source, bool isReadOnly = false) -> Aspire.Hosting.ApplicationModel.IResourceBuilder<Aspire.Hosting.ApplicationModel.GarnetResource!>!
static Aspire.Hosting.GarnetBuilderExtensions.WithDataVolume(this Aspire.Hosting.ApplicationModel.IResourceBuilder<Aspire.Hosting.ApplicationModel.GarnetResource!>! builder, string? name = null, bool isReadOnly = false) -> Aspire.Hosting.ApplicationModel.IResourceBuilder<Aspire.Hosting.ApplicationModel.GarnetResource!>!
static Aspire.Hosting.GarnetBuilderExtensions.WithPersistence(this Aspire.Hosting.ApplicationModel.IResourceBuilder<Aspire.Hosting.ApplicationModel.GarnetResource!>! builder, System.TimeSpan? interval = null, long keysChangedThreshold = 1) -> Aspire.Hosting.ApplicationModel.IResourceBuilder<Aspire.Hosting.ApplicationModel.GarnetResource!>!
12 changes: 3 additions & 9 deletions src/Aspire.Hosting.Garnet/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
#nullable enable
Aspire.Hosting.ApplicationModel.GarnetResource
Aspire.Hosting.ApplicationModel.GarnetResource.ConnectionStringExpression.get -> Aspire.Hosting.ApplicationModel.ReferenceExpression!
Aspire.Hosting.ApplicationModel.GarnetResource.PrimaryEndpoint.get -> Aspire.Hosting.ApplicationModel.EndpointReference!
Aspire.Hosting.ApplicationModel.GarnetResource.GarnetResource(string! name) -> void
Aspire.Hosting.GarnetBuilderExtensions
static Aspire.Hosting.GarnetBuilderExtensions.AddGarnet(this Aspire.Hosting.IDistributedApplicationBuilder! builder, string! name, int? port = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder<Aspire.Hosting.ApplicationModel.GarnetResource!>!
static Aspire.Hosting.GarnetBuilderExtensions.WithDataBindMount(this Aspire.Hosting.ApplicationModel.IResourceBuilder<Aspire.Hosting.ApplicationModel.GarnetResource!>! builder, string! source, bool isReadOnly = false) -> Aspire.Hosting.ApplicationModel.IResourceBuilder<Aspire.Hosting.ApplicationModel.GarnetResource!>!
static Aspire.Hosting.GarnetBuilderExtensions.WithDataVolume(this Aspire.Hosting.ApplicationModel.IResourceBuilder<Aspire.Hosting.ApplicationModel.GarnetResource!>! builder, string? name = null, bool isReadOnly = false) -> Aspire.Hosting.ApplicationModel.IResourceBuilder<Aspire.Hosting.ApplicationModel.GarnetResource!>!
static Aspire.Hosting.GarnetBuilderExtensions.WithPersistence(this Aspire.Hosting.ApplicationModel.IResourceBuilder<Aspire.Hosting.ApplicationModel.GarnetResource!>! builder, System.TimeSpan? interval = null, long keysChangedThreshold = 1) -> Aspire.Hosting.ApplicationModel.IResourceBuilder<Aspire.Hosting.ApplicationModel.GarnetResource!>!
static Aspire.Hosting.GarnetBuilderExtensions.WithPersistence(this Aspire.Hosting.ApplicationModel.IResourceBuilder<Aspire.Hosting.ApplicationModel.GarnetResource!>! builder, System.TimeSpan? interval = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder<Aspire.Hosting.ApplicationModel.GarnetResource!>!
*REMOVED*static Aspire.Hosting.GarnetBuilderExtensions.WithPersistence(this Aspire.Hosting.ApplicationModel.IResourceBuilder<Aspire.Hosting.ApplicationModel.GarnetResource!>! builder, System.TimeSpan? interval = null, long keysChangedThreshold = 1) -> Aspire.Hosting.ApplicationModel.IResourceBuilder<Aspire.Hosting.ApplicationModel.GarnetResource!>!
static Aspire.Hosting.GarnetBuilderExtensions.WithPersistence(this Aspire.Hosting.ApplicationModel.IResourceBuilder<Aspire.Hosting.ApplicationModel.GarnetResource!>! builder, System.TimeSpan? interval, long keysChangedThreshold) -> Aspire.Hosting.ApplicationModel.IResourceBuilder<Aspire.Hosting.ApplicationModel.GarnetResource!>!
8 changes: 4 additions & 4 deletions tests/Aspire.Hosting.Garnet.Tests/AddGarnetTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ public void WithDataVolumeAddsPersistenceAnnotation()
argsAnnotation.Callback(new CommandLineArgsCallbackContext(args));
}

Assert.Equal("--save 60 1".Split(" "), args);
Assert.Equal("--checkpointdir /data/checkpoints --recover --aof --aof-commit-freq 60000".Split(" "), args);
}

[Fact]
Expand Down Expand Up @@ -207,7 +207,7 @@ public void WithDataBindMountAddsPersistenceAnnotation()
argsAnnotation.Callback(new CommandLineArgsCallbackContext(args));
}

Assert.Equal("--save 60 1".Split(" "), args);
Assert.Equal("--checkpointdir /data/checkpoints --recover --aof --aof-commit-freq 60000".Split(" "), args);
}

[Fact]
Expand All @@ -228,7 +228,7 @@ public void WithPersistenceReplacesPreviousAnnotationInstances()
using var builder = TestDistributedApplicationBuilder.Create();
var garnet = builder.AddGarnet("myGarnet")
.WithDataVolume()
.WithPersistence(TimeSpan.FromSeconds(10), 2);
.WithPersistence(TimeSpan.FromSeconds(10));

Assert.True(garnet.Resource.TryGetAnnotationsOfType<CommandLineArgsCallbackAnnotation>(out var argsCallbacks));

Expand All @@ -239,7 +239,7 @@ public void WithPersistenceReplacesPreviousAnnotationInstances()
argsAnnotation.Callback(new CommandLineArgsCallbackContext(args));
}

Assert.Equal("--save 10 2".Split(" "), args);
Assert.Equal("--checkpointdir /data/checkpoints --recover --aof --aof-commit-freq 10000".Split(" "), args);
}

[Fact]
Expand Down
Loading