Skip to content

Commit 5436519

Browse files
authored
fix: FileSystemJsonCheckpointStore does not flush to disk on Checkpoint creation (#3439)
1 parent a3a9147 commit 5436519

2 files changed

Lines changed: 58 additions & 0 deletions

File tree

dotnet/src/Microsoft.Agents.AI.Workflows/Checkpointing/FileSystemJsonCheckpointStore.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ public override async ValueTask<CheckpointInfo> CreateCheckpointAsync(string run
125125
JsonSerializer.Serialize(this._indexFile!, key, KeyTypeInfo);
126126
byte[] bytes = Encoding.UTF8.GetBytes(Environment.NewLine);
127127
await this._indexFile!.WriteAsync(bytes, 0, bytes.Length, CancellationToken.None).ConfigureAwait(false);
128+
await this._indexFile!.FlushAsync(CancellationToken.None).ConfigureAwait(false);
128129

129130
return key;
130131
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
3+
using System;
4+
using System.IO;
5+
using System.Text.Json;
6+
using System.Threading.Tasks;
7+
using FluentAssertions;
8+
using Microsoft.Agents.AI.Workflows.Checkpointing;
9+
10+
namespace Microsoft.Agents.AI.Workflows.UnitTests;
11+
12+
public sealed class FileSystemJsonCheckpointStoreTests
13+
{
14+
[Fact]
15+
public async Task CreateCheckpointAsync_ShouldPersistIndexToDiskBeforeDisposeAsync()
16+
{
17+
// Arrange
18+
DirectoryInfo tempDir = new(Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()));
19+
FileSystemJsonCheckpointStore? store = null;
20+
21+
try
22+
{
23+
store = new(tempDir);
24+
string runId = Guid.NewGuid().ToString("N");
25+
JsonElement testData = JsonSerializer.SerializeToElement(new { test = "data" });
26+
27+
// Act
28+
CheckpointInfo checkpoint = await store.CreateCheckpointAsync(runId, testData);
29+
30+
// Assert - Check the file size before disposing to verify data was flushed to disk
31+
// The index.jsonl file is held exclusively by the store, so we check via FileInfo
32+
string indexPath = Path.Combine(tempDir.FullName, "index.jsonl");
33+
FileInfo indexFile = new(indexPath);
34+
indexFile.Refresh();
35+
long fileSizeBeforeDispose = indexFile.Length;
36+
37+
// Data should already be on disk (file size > 0) before we dispose
38+
fileSizeBeforeDispose.Should().BeGreaterThan(0, "index.jsonl should be flushed to disk after CreateCheckpointAsync");
39+
40+
// Dispose to release file lock before final verification
41+
store.Dispose();
42+
store = null;
43+
44+
string[] lines = File.ReadAllLines(indexPath);
45+
lines.Should().HaveCount(1);
46+
lines[0].Should().Contain(checkpoint.CheckpointId);
47+
}
48+
finally
49+
{
50+
store?.Dispose();
51+
if (tempDir.Exists)
52+
{
53+
tempDir.Delete(recursive: true);
54+
}
55+
}
56+
}
57+
}

0 commit comments

Comments
 (0)