-
Notifications
You must be signed in to change notification settings - Fork 43
Expand file tree
/
Copy pathClient.cs
More file actions
83 lines (75 loc) · 3.64 KB
/
Client.cs
File metadata and controls
83 lines (75 loc) · 3.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
// Standalone client CLI (dotnet run --project Client.csproj is convenient,
// but for the demo this lives as a static method on the worker assembly,
// invoked via `dotnet run -- <args>` after switching the project's OutputType
// or via `dotnet TriageWorker.dll client <args>` once published.
//
// Listing pending approval workflows: use the Temporal CLI directly.
using Temporalio.Client;
using TemporalioSamples.ToolRegistryIncidentTriage;
namespace TemporalioSamples.ToolRegistryIncidentTriage;
public static class ClientCli
{
public static async Task<int> RunAsync(string[] args)
{
if (args.Length == 0)
{
Console.Error.WriteLine("Usage: client <approve|reject|trigger> ...");
return 1;
}
var client = await MakeClientAsync().ConfigureAwait(false);
var cmd = args[0];
var rest = args.Skip(1).ToArray();
return cmd switch
{
"approve" when rest.Length >= 2 => await DecideAsync(client, "approved", rest[0], string.Join(" ", rest.Skip(1))),
"reject" when rest.Length >= 2 => await DecideAsync(client, "rejected", rest[0], string.Join(" ", rest.Skip(1))),
"trigger" when rest.Length >= 2 => await TriggerAsync(client, rest[0], rest[1]),
_ => Usage(cmd),
};
}
private static int Usage(string cmd)
{
Console.Error.WriteLine($"Unknown or malformed command: {cmd}");
Console.Error.WriteLine("Usage: client <approve|reject|trigger> ...");
return 1;
}
private static async Task<TemporalClient> MakeClientAsync()
{
var address = Environment.GetEnvironmentVariable("TEMPORAL_ADDRESS") ?? throw new InvalidOperationException("TEMPORAL_ADDRESS missing");
var ns = Environment.GetEnvironmentVariable("TEMPORAL_NAMESPACE") ?? throw new InvalidOperationException("TEMPORAL_NAMESPACE missing");
var apiKey = Environment.GetEnvironmentVariable("TEMPORAL_API_KEY") ?? throw new InvalidOperationException("TEMPORAL_API_KEY missing");
return await TemporalClient.ConnectAsync(new()
{
TargetHost = address,
Namespace = ns,
ApiKey = apiKey,
Tls = new() { },
});
}
private static async Task<int> DecideAsync(TemporalClient client, string decision, string workflowId, string reason)
{
var handle = client.GetWorkflowHandle<ApprovalWorkflow>(workflowId);
await handle.SignalAsync(wf => wf.ApprovalDecisionAsync(new ApprovalResponse(decision, reason)));
Console.WriteLine($"signaled {workflowId}: {decision} — {reason}");
return 0;
}
private static async Task<int> TriggerAsync(TemporalClient client, string alertname, string service)
{
var taskQueue = Environment.GetEnvironmentVariable("TEMPORAL_TASK_QUEUE") ?? "triage-dotnet";
var wfId = $"triage-{alertname.ToLowerInvariant()}-{service.ToLowerInvariant()}";
var alert = new AlertPayload(
Status: "firing",
Labels: new() { ["alertname"] = alertname, ["service"] = service, ["severity"] = "critical", ["runbook"] = "synthetic" },
Annotations: new()
{
["summary"] = $"Synthetic test alert for {service}",
["description"] = "Triggered manually via Client to exercise the triage flow.",
},
StartsAt: DateTime.UtcNow.ToString("o"));
var handle = await client.StartWorkflowAsync(
(IncidentTriageWorkflow w) => w.RunAsync(alert),
new(id: wfId, taskQueue: taskQueue));
Console.WriteLine($"started triage workflow: {handle.Id} on {taskQueue}");
return 0;
}
}