Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
Prev Previous commit
Next Next commit
Copilot comments + changed DateTime usage to DateTimeOffset
  • Loading branch information
amnguye committed Dec 4, 2025
commit e1228157d375234e9878cd8d01c8e7ba4e5f9592
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ internal class ContainerScanInfo

public DateTimeOffset PollingStartTime { get; set; }

public DateTime LastSweepCycleLatestModified { get; set; }
public DateTimeOffset LastSweepCycleLatestModified { get; set; }

public DateTime CurrentSweepCycleLatestModified { get; set; }
public DateTimeOffset CurrentSweepCycleLatestModified { get; set; }

public string ContinuationToken { get; set; }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace Microsoft.Azure.WebJobs.Extensions.Storage.Blobs.Listeners
{
internal interface IBlobScanInfoManager
{
Task<DateTime?> LoadLatestScanAsync(string storageAccountName, string containerName);
Task UpdateLatestScanAsync(string storageAccountName, string containerName, DateTime scanInfo);
Task<DateTimeOffset?> LoadLatestScanAsync(string storageAccountName, string containerName);
Task UpdateLatestScanAsync(string storageAccountName, string containerName, DateTimeOffset scanInfo);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ private static class Logger
LoggerMessage.Define<string>(LogLevel.Debug, new EventId(3, nameof(ContainerDoesNotExist)),
"Container '{containerName}' does not exist.");

public static void InitializedScanInfo(ILogger<BlobListener> logger, string container, DateTime latestScanInfo) =>
public static void InitializedScanInfo(ILogger<BlobListener> logger, string container, DateTimeOffset latestScanInfo) =>
_initializedScanInfo(logger, container, latestScanInfo.ToString(Constants.DateTimeFormatString, CultureInfo.InvariantCulture), null);

public static void PollBlobContainer(ILogger<BlobListener> logger, string container, DateTime latestScanInfo, string clientRequestId, int blobCount, long latencyInMilliseconds, bool hasContinuationToken) =>
public static void PollBlobContainer(ILogger<BlobListener> logger, string container, DateTimeOffset latestScanInfo, string clientRequestId, int blobCount, long latencyInMilliseconds, bool hasContinuationToken) =>
_pollBlobContainer(logger, latestScanInfo.ToString(Constants.DateTimeFormatString, CultureInfo.InvariantCulture), container, clientRequestId, blobCount, latencyInMilliseconds, hasContinuationToken, null);

public static void ContainerDoesNotExist(ILogger<BlobListener> logger, string container) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public async Task RegisterAsync(BlobServiceClient blobServiceClient, BlobContain
if (!_scanInfo.TryGetValue(container, out ContainerScanInfo containerScanInfo))
{
// First, try to load serialized scanInfo for this container.
DateTime? latestStoredScan = await _blobScanInfoManager.LoadLatestScanAsync(blobServiceClient.AccountName, container.Name).ConfigureAwait(false);
DateTimeOffset? latestStoredScan = await _blobScanInfoManager.LoadLatestScanAsync(blobServiceClient.AccountName, container.Name).ConfigureAwait(false);

containerScanInfo = new ContainerScanInfo()
{
Expand Down Expand Up @@ -138,7 +138,7 @@ private async Task PollAndNotify(BlobContainerClient container, ContainerScanInf
List<BlobNotification> failedNotifications, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
DateTime lastScan = containerScanInfo.LastSweepCycleLatestModified;
DateTimeOffset lastScan = containerScanInfo.LastSweepCycleLatestModified;

// For tracking
string clientRequestId = Guid.NewGuid().ToString();
Expand All @@ -154,7 +154,7 @@ private async Task PollAndNotify(BlobContainerClient container, ContainerScanInf
// if the 'LatestModified' has changed, update it in the manager
if (containerScanInfo.LastSweepCycleLatestModified > lastScan)
{
DateTime latestScan = containerScanInfo.LastSweepCycleLatestModified;
DateTimeOffset latestScan = containerScanInfo.LastSweepCycleLatestModified;

// It's possible that we had some blobs that we failed to move to the queue. We want to make sure
// we continue to find these if the host needs to restart.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ public StorageBlobScanInfoManager(string hostId, BlobServiceClient blobClient)
_blobContainerClient = blobClient.GetBlobContainerClient(HostContainerNames.Hosts);
}

public async Task<DateTime?> LoadLatestScanAsync(string storageAccountName, string containerName)
public async Task<DateTimeOffset?> LoadLatestScanAsync(string storageAccountName, string containerName)
{
var scanInfoBlob = GetScanInfoBlobReference(storageAccountName, containerName);
DateTime? latestScan = null;
DateTimeOffset? latestScan = null;
try
{
string scanInfoLine = await scanInfoBlob.DownloadTextAsync(CancellationToken.None).ConfigureAwait(false);
Expand Down Expand Up @@ -74,7 +74,7 @@ public StorageBlobScanInfoManager(string hostId, BlobServiceClient blobClient)
}
}

public async Task UpdateLatestScanAsync(string storageAccountName, string containerName, DateTime latestScan)
public async Task UpdateLatestScanAsync(string storageAccountName, string containerName, DateTimeOffset latestScan)
{
string scanInfoLine;
ScanInfo scanInfo = new ScanInfo
Expand Down Expand Up @@ -109,7 +109,7 @@ private BlockBlobClient GetScanInfoBlobReference(string storageAccountName, stri

internal class ScanInfo
{
public DateTime LatestScan { get; set; }
public DateTimeOffset LatestScan { get; set; }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ public async Task RegisterAsync_InitializesWithScanInfoManager()
// delay slightly so we guarantee a later timestamp
await Task.Delay(10);

await scanInfoManager.UpdateLatestScanAsync(AccountName, ContainerName, DateTime.UtcNow);
await scanInfoManager.UpdateLatestScanAsync(AccountName, ContainerName, DateTimeOffset.UtcNow);
await product.RegisterAsync(_blobClientMock.Object, container, executor, CancellationToken.None);

// delay slightly so we guarantee a later timestamp
Expand Down Expand Up @@ -404,7 +404,7 @@ public async Task ExecuteAsync_UpdatesScanInfo_WithEarliestFailure()

RunExecuteWithMultiPollingInterval(expectedNames, product, executor, testScanBlobLimitPerPoll);

DateTime? storedTime = await testScanInfoManager.LoadLatestScanAsync(accountName, ContainerName);
DateTimeOffset? storedTime = await testScanInfoManager.LoadLatestScanAsync(accountName, ContainerName);
Assert.True(storedTime < earliestErrorTime);
Assert.AreEqual(1, testScanInfoManager.UpdateCounts[accountName][ContainerName]);
_blobContainerMock.Verify(x => x.GetBlobsAsync(It.IsAny<BlobTraits>(), It.IsAny<BlobStates>(), It.IsAny<string>(), It.IsAny<CancellationToken>()),
Expand All @@ -429,7 +429,7 @@ public async Task ExecuteAsync_PollNewBlobsAsync_ContinuationTokenUpdatedBlobs()
containerMock.Setup(x => x.Name).Returns(ContainerName);
containerMock.Setup(x => x.AccountName).Returns(AccountName);

// Create first pages of blob to list from
// Create first page of blobs to list from
List<BlobItem> blobItems = new List<BlobItem>();
List<string> expectedNames = new List<string>();
for (int i = 0; i < 5; i++)
Expand Down Expand Up @@ -460,7 +460,7 @@ public async Task ExecuteAsync_PollNewBlobsAsync_ContinuationTokenUpdatedBlobs()
// Add blob with LMT after polling started to the second polling expected names.
secondSetExpectedNames.Add(blobNameWithLmtAfterStartedPolling);

// Set up GetBlobsAsync to return pages with contination token for each page, but not at the end of each polling
// Set up GetBlobsAsync to return pages with continuation token for each page, but not at the end of each polling
containerMock.SetupSequence(x => x.GetBlobsAsync(It.IsAny<BlobTraits>(), It.IsAny<BlobStates>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
// First polling
.Returns(() =>
Expand Down Expand Up @@ -488,7 +488,7 @@ public async Task ExecuteAsync_PollNewBlobsAsync_ContinuationTokenUpdatedBlobs()
RunExecuteWithMultiPollingInterval(expectedNames, product, executor, blobItems.Count);

// Wait 5 seconds to ensure that the blob with LMT after polling started is detected as a new blob.
Thread.Sleep(5000);
await Task.Delay(TimeSpan.FromSeconds(5));

// Act / Assert - Second Polling
// We expect all the blobs we updated above to be detected and the blob that was created after the first polling started that wasn't detected
Expand Down Expand Up @@ -619,23 +619,23 @@ public Task<FunctionResult> ExecuteAsync(BlobTriggerExecutorContext value, Cance

private class TestBlobScanInfoManager : IBlobScanInfoManager
{
private IDictionary<string, IDictionary<string, DateTime>> _latestScans;
private IDictionary<string, IDictionary<string, DateTimeOffset>> _latestScans;

public TestBlobScanInfoManager()
{
_latestScans = new Dictionary<string, IDictionary<string, DateTime>>();
_latestScans = new Dictionary<string, IDictionary<string, DateTimeOffset>>();
UpdateCounts = new Dictionary<string, IDictionary<string, int>>();
}

public IDictionary<string, IDictionary<string, int>> UpdateCounts { get; private set; }

public Task<DateTime?> LoadLatestScanAsync(string storageAccountName, string containerName)
public Task<DateTimeOffset?> LoadLatestScanAsync(string storageAccountName, string containerName)
{
DateTime? value = null;
IDictionary<string, DateTime> accounts;
DateTimeOffset? value = null;
IDictionary<string, DateTimeOffset> accounts;
if (_latestScans.TryGetValue(storageAccountName, out accounts))
{
DateTime latestScan;
DateTimeOffset latestScan;
if (accounts.TryGetValue(containerName, out latestScan))
{
value = latestScan;
Expand All @@ -645,20 +645,20 @@ public TestBlobScanInfoManager()
return Task.FromResult(value);
}

public Task UpdateLatestScanAsync(string storageAccountName, string containerName, DateTime latestScan)
public Task UpdateLatestScanAsync(string storageAccountName, string containerName, DateTimeOffset latestScan)
{
SetScanInfo(storageAccountName, containerName, latestScan);
IncrementCount(storageAccountName, containerName);
return Task.FromResult(0);
}

public void SetScanInfo(string storageAccountName, string containerName, DateTime latestScan)
public void SetScanInfo(string storageAccountName, string containerName, DateTimeOffset latestScan)
{
IDictionary<string, DateTime> containers;
IDictionary<string, DateTimeOffset> containers;

if (!_latestScans.TryGetValue(storageAccountName, out containers))
{
_latestScans[storageAccountName] = new Dictionary<string, DateTime>();
_latestScans[storageAccountName] = new Dictionary<string, DateTimeOffset>();
containers = _latestScans[storageAccountName];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ public async Task UpdateLatestScan_Updates()
var container = blobServiceClient.GetBlobContainerClient(HostContainerNames.Hosts);
await container.CreateIfNotExistsAsync();

DateTime now = DateTime.UtcNow;
DateTime past = now.AddMinutes(-1);
DateTimeOffset now = DateTimeOffset.UtcNow;
DateTimeOffset past = now.AddMinutes(-1);

var blob = GetBlockBlobReference(blobServiceClient, hostId, storageAccountName, containerName);
await blob.UploadTextAsync(string.Format("{{ 'LatestScan' : '{0}' }}", past.ToString("o")));
Expand All @@ -118,7 +118,7 @@ public async Task UpdateLatestScan_Updates()

var scanInfo = GetBlockBlobReference(blobServiceClient, hostId, storageAccountName, containerName).DownloadText();
var scanInfoJson = JObject.Parse(scanInfo);
var storedTime = (DateTime)scanInfoJson["LatestScan"];
var storedTime = (DateTimeOffset)scanInfoJson["LatestScan"];

Assert.AreEqual(now, storedTime);
Assert.AreEqual(now, await manager.LoadLatestScanAsync(storageAccountName, containerName));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore"/>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing"/>
<PackageReference Include="Microsoft.Azure.WebJobs.Host.Storage" />
</ItemGroup>

Expand Down
Loading