Skip to content

Commit 9b5d1f9

Browse files
authored
feat(monitoring): aggregate schedule/progress into monitor blobs and expose GET monitor API (#124)
- Add SyncMonitoringAggregationService: drain log-schedule and per-state progress queues, merge into per-job JSON under the monitor container (ETag retries) - Add AggregateSyncMonitoring timer and GET monitor/{area}/{id?}/{schedule?} - Add monitor response models and live TableVersion rows from SQL - Add ProcessGlobalChangeTrackingScheduleNextRun (Cronos) for next-run estimates - Centralize NCRONTAB strings and custom schedule binding in Constants.Schedules - Report Created progress before queueing sync; set JSON content-type on progress blobs - Persist sync.TableVersion.Updated and align MERGE/SELECT; fix empty schedule fallback - Reference Cronos in Directory.Packages.props and csproj
1 parent 22a09f4 commit 9b5d1f9

19 files changed

Lines changed: 1118 additions & 22 deletions

src/Directory.Packages.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,6 @@
1919
<PackageVersion Include="Microsoft.Azure.Functions.Worker.Sdk" Version="2.0.7" />
2020
<PackageVersion Include="Microsoft.Data.SqlClient" Version="7.0.0" />
2121
<PackageVersion Include="NuGetizer" Version="1.4.7" />
22+
<PackageVersion Include="Cronos" Version="0.11.1" />
2223
</ItemGroup>
2324
</Project>

src/SqlBulkSyncFunction/Constants.cs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,34 @@ public static class Queues
2222
/// </summary>
2323
public const string SyncJobProgressQueue = "syncjobprogress";
2424
}
25+
/// <summary>
26+
/// NCRONTAB expressions and configuration keys for <see cref="Functions.ProcessGlobalChangeTrackingSchedule"/> timer triggers.
27+
/// </summary>
28+
public static class Schedules
29+
{
30+
/// <summary>
31+
/// Configuration / environment key for the <c>Custom</c> schedule (same as the timer binding placeholder without % delimiters).
32+
/// </summary>
33+
public const string CustomScheduleConfigurationKey = "ProcessGlobalChangeTrackingSchedule";
34+
35+
/// <summary>
36+
/// Timer trigger binding for the custom schedule: <c>%ProcessGlobalChangeTrackingSchedule%</c>.
37+
/// </summary>
38+
public const string CustomScheduleTimerTrigger = "%" + CustomScheduleConfigurationKey + "%";
39+
40+
/// <summary>NCRONTAB for <c>Midnight</c> (<c>0 0 0 * * *</c>).</summary>
41+
public const string MidnightCron = "0 0 0 * * *";
42+
43+
/// <summary>NCRONTAB for <c>Noon</c> (<c>0 0 12 * * *</c>).</summary>
44+
public const string NoonCron = "0 0 12 * * *";
45+
46+
/// <summary>NCRONTAB for <c>EveryFiveMinutes</c> (<c>5 */5 * * * *</c>).</summary>
47+
public const string EveryFiveMinutesCron = "5 */5 * * * *";
48+
49+
/// <summary>NCRONTAB for <c>EveryHour</c> (<c>10 0 * * * *</c>).</summary>
50+
public const string EveryHourCron = "10 0 * * * *";
51+
}
52+
2553
public static class Containers
2654
{
2755
/// <summary>
@@ -30,5 +58,19 @@ public static class Containers
3058
public const string SyncJob = "syncjob";
3159

3260
public const string SyncSchedule = "syncschedule";
61+
62+
/// <summary>
63+
/// Blob container for per-job monitoring aggregates (written by the aggregation timer).
64+
/// </summary>
65+
public const string Monitor = "monitor";
66+
}
67+
68+
/// <summary>
69+
/// Content types for Azure Blob uploads.
70+
/// </summary>
71+
public static class BlobContentTypes
72+
{
73+
/// <summary>JSON documents (UTF-8).</summary>
74+
public const string Json = "application/json; charset=utf-8";
3375
}
3476
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using System.Threading;
2+
using System.Threading.Tasks;
3+
using Microsoft.Azure.Functions.Worker;
4+
using SqlBulkSyncFunction.Services;
5+
6+
namespace SqlBulkSyncFunction.Functions;
7+
8+
/// <summary>
9+
/// Timer that drains schedule and progress queues in order and refreshes per-job aggregate blobs under the monitor container.
10+
/// </summary>
11+
public sealed class AggregateSyncMonitoring(SyncMonitoringAggregationService aggregationService)
12+
{
13+
/// <summary>
14+
/// Runs every minute on the minute (UTC).
15+
/// </summary>
16+
[Function(nameof(AggregateSyncMonitoring))]
17+
public Task Run(
18+
#pragma warning disable IDE0060 // Remove unused parameter
19+
[TimerTrigger("0 */1 * * * *")] TimerInfo timerInfo,
20+
#pragma warning restore IDE0060 // Remove unused parameter
21+
CancellationToken cancellationToken
22+
)
23+
=> aggregationService.ProcessAllQueuesAsync(cancellationToken);
24+
}

0 commit comments

Comments
 (0)