@prorigo/protrak-forge 0.3.5 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,77 +0,0 @@
1
- # Scheduler Program Pattern
2
-
3
- ## When to Use
4
- Use this pattern for background jobs that run on a schedule (cron). Common uses:
5
- - Send daily reminder notifications
6
- - Auto-close overdue instances
7
- - Compute/recalculate aggregate values from related instances (see [Aggregate Related Instances](./aggregate-related-instances.md) for the canonical roll-up shape)
8
- - Sync data with external systems
9
-
10
- ## Program Types
11
- Applies to: `Scheduler`
12
-
13
- ## Services Used
14
- - `IInstanceService` — to query and update instances
15
- - `INotificationService` — to send scheduled notifications
16
- - `IQueryBuilderService` — to filter instances
17
-
18
- ## Code Example
19
-
20
- ```csharp
21
- using Prorigo.Protrak.API.Contracts;
22
- using System;
23
- using System.Linq;
24
- using System.Threading.Tasks;
25
-
26
- namespace MyProject.Customization
27
- {
28
- public class SendDailyOverdueReminders : ISchedulerProgramAsync
29
- {
30
- public IInstanceService InstanceService { get; set; }
31
- public INotificationService NotificationService { get; set; }
32
- public IQueryBuilderService QueryBuilderService { get; set; }
33
-
34
- public async Task RunAsync()
35
- {
36
- var today = DateTime.UtcNow.Date;
37
- var filter = QueryBuilderService.CreateAttributeFilterExpression(
38
- "DueDate", today.ToString("yyyy-MM-dd"), FilterOperator.LessThanOrEqual);
39
-
40
- var query = new InstanceQuery
41
- {
42
- TypeName = "WorkOrder",
43
- Filter = filter,
44
- StateName = "Open",
45
- Take = 500
46
- };
47
-
48
- var overdueItems = await InstanceService.GetInstancesAsync(query);
49
- if (overdueItems?.Data == null || overdueItems.Data.Length == 0)
50
- return;
51
-
52
- foreach (var item in overdueItems.Data)
53
- {
54
- var assignee = item.Attributes?
55
- .FirstOrDefault(a => a.Name == "AssignedEngineer")?.Value?.ToString();
56
-
57
- if (string.IsNullOrEmpty(assignee)) continue;
58
-
59
- await NotificationService.SendNotificationAsync(
60
- new[] { assignee },
61
- "Overdue Work Order",
62
- $"Work Order {item.TrackingId} is overdue. Please take action.",
63
- item.Id
64
- );
65
- }
66
- }
67
- }
68
- }
69
- ```
70
-
71
- ## Key Rules
72
- - The `Run()` / `RunAsync()` method takes no parameters
73
- - Use `ISchedulerProgramAsync` for async operations
74
- - Avoid long-running loops — use `Take` to limit batch sizes
75
- - Log or notify on errors so failures are visible
76
- - Consider idempotency: what happens if the scheduler runs twice?
77
- - When the scheduler walks parent → related instances and reads attributes off each child, use `RelatedQueryBuilder.Select(...)` in a single `GetRelatedInstancesAsync` call. **Do not** fan out to `GetInstanceAsync` per related id — that's an N+1 anti-pattern. See [Aggregate Related Instances](./aggregate-related-instances.md).