Skip to content

Commit c53d12b

Browse files
committed
Make Copilot Workspace output compile
1 parent 14604f0 commit c53d12b

File tree

6 files changed

+187
-140
lines changed

6 files changed

+187
-140
lines changed

Diff for: updates_and_signals/safe_message_handlers/src/activities.ts

+17-16
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,34 @@
1-
import { proxyActivities } from '@temporalio/workflow';
2-
import { ActivityInput as AllocateNodesToJobInput } from './interfaces';
1+
export interface AllocateNodesToJobInput {
2+
nodes: string[];
3+
jobName: string;
4+
}
35

4-
// Activities with TypeScript syntax and Temporal TypeScript SDK specifics
5-
const { allocateNodesToJob, deallocateNodesForJob, findBadNodes } = proxyActivities<{
6-
allocateNodesToJob(input: AllocateNodesToJobInput): Promise<void>;
7-
deallocateNodesForJob(input: DeallocateNodesForJobInput): Promise<void>;
8-
findBadNodes(input: FindBadNodesInput): Promise<string[]>;
9-
}>({
10-
startToCloseTimeout: '1 minute',
11-
});
6+
export interface DeallocateNodesForJobInput {
7+
nodes: string[];
8+
jobName: string;
9+
}
10+
11+
export interface FindBadNodesInput {
12+
nodesToCheck: string[];
13+
}
1214

1315
export async function allocateNodesToJob(input: AllocateNodesToJobInput): Promise<void> {
1416
console.log(`Assigning nodes ${input.nodes} to job ${input.jobName}`);
15-
await new Promise(resolve => setTimeout(resolve, 100)); // Simulate async operation
17+
await new Promise((resolve) => setTimeout(resolve, 100)); // Simulate async operation
1618
}
1719

1820
export async function deallocateNodesForJob(input: DeallocateNodesForJobInput): Promise<void> {
1921
console.log(`Deallocating nodes ${input.nodes} from job ${input.jobName}`);
20-
await new Promise(resolve => setTimeout(resolve, 100)); // Simulate async operation
22+
await new Promise((resolve) => setTimeout(resolve, 100)); // Simulate async operation
2123
}
2224

2325
export async function findBadNodes(input: FindBadNodesInput): Promise<string[]> {
24-
await new Promise(resolve => setTimeout(resolve, 100)); // Simulate async operation
25-
const badNodes = input.nodesToCheck.filter(n => parseInt(n) % 5 === 0);
26+
await new Promise((resolve) => setTimeout(resolve, 100)); // Simulate async operation
27+
const badNodes = input.nodesToCheck.filter((n) => parseInt(n) % 5 === 0);
2628
if (badNodes.length) {
2729
console.log(`Found bad nodes: ${badNodes}`);
2830
} else {
29-
console.log("No new bad nodes found.");
31+
console.log('No new bad nodes found.');
3032
}
3133
return badNodes;
3234
}
33-
+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { Connection, Client, WorkflowHandle } from '@temporalio/client';
2+
import * as workflow from './workflows';
3+
4+
async function doClusterLifecycle(wf: WorkflowHandle, delaySeconds?: number): Promise<void> {
5+
await wf.signal(workflow.startClusterSignal);
6+
7+
const allocationUpdates: Promise<any>[] = [];
8+
for (let i = 0; i < 6; i++) {
9+
allocationUpdates.push(
10+
wf.executeUpdate(workflow.allocateNodesToJobUpdate, { args: [{ numNodes: 2, jobName: `task-${i}` }] })
11+
);
12+
}
13+
await Promise.all(allocationUpdates);
14+
15+
if (delaySeconds) {
16+
await new Promise((resolve) => setTimeout(resolve, delaySeconds * 1000));
17+
}
18+
19+
const deletionUpdates: Promise<any>[] = [];
20+
for (let i = 0; i < 6; i++) {
21+
deletionUpdates.push(wf.executeUpdate(workflow.deleteJobUpdate, { args: [{ jobName: `task-${i}` }] }));
22+
}
23+
await Promise.all(deletionUpdates);
24+
25+
await wf.signal(workflow.shutdownClusterSignal);
26+
}
27+
async function main() {
28+
const connection = await Connection.connect({ address: 'localhost:7233' });
29+
const client = new Client({ connection });
30+
31+
// Define the workflow handle
32+
const wfHandle = await client.workflow.start(workflow.clusterManagerWorkflow, {
33+
args: [{ testContinueAsNew: true }],
34+
taskQueue: 'tq',
35+
workflowId: 'cluster-management-workflow',
36+
});
37+
38+
// Start the cluster lifecycle
39+
await doClusterLifecycle(wfHandle);
40+
}
41+
42+
main().catch((err) => {
43+
console.error(err);
44+
process.exit(1);
45+
});

Diff for: updates_and_signals/safe_message_handlers/src/starter.ts

-20
This file was deleted.

Diff for: updates_and_signals/safe_message_handlers/src/worker.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@ import path from 'path';
33

44
async function run() {
55
const worker = await Worker.create({
6-
workflowsPath: path.join(__dirname, './workflows'),
7-
activitiesPath: path.join(__dirname, './activities'),
6+
workflowsPath: path.join(__dirname, './workflows.ts'),
87
taskQueue: 'safe-message-handlers-task-queue',
98
});
109

Diff for: updates_and_signals/safe_message_handlers/src/workflow.ts

-102
This file was deleted.
+124
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
// This file contains the TypeScript port of the Python workflow for managing cluster updates and signals
2+
3+
import {
4+
proxyActivities,
5+
defineSignal,
6+
defineUpdate,
7+
defineQuery,
8+
setHandler,
9+
condition,
10+
sleep,
11+
} from '@temporalio/workflow';
12+
import type * as activities from './activities';
13+
14+
interface ClusterManagerState {
15+
clusterStarted: boolean;
16+
clusterShutdown: boolean;
17+
nodes: { [key: string]: string | null };
18+
jobsAdded: Set<string>;
19+
maxAssignedNodes: number;
20+
}
21+
22+
interface ClusterManagerInput {
23+
state?: ClusterManagerState;
24+
testContinueAsNew: boolean;
25+
}
26+
27+
interface ClusterManagerResult {
28+
maxAssignedNodes: number;
29+
numCurrentlyAssignedNodes: number;
30+
numBadNodes: number;
31+
}
32+
33+
export interface AllocateNodesToJobInput {
34+
numNodes: number;
35+
jobName: string;
36+
}
37+
38+
interface DeleteJobInput {
39+
jobName: string;
40+
}
41+
42+
export interface ClusterManagerWorkflowInput {
43+
testContinueAsNew: boolean;
44+
}
45+
46+
export interface ClusterManagerWorkflowResult {
47+
maxAssignedNodes: number;
48+
numCurrentlyAssignedNodes: number;
49+
numBadNodes: number;
50+
}
51+
52+
// Message-handling API
53+
export const startClusterSignal = defineSignal('startCluster');
54+
export const shutdownClusterSignal = defineSignal('shutdownCluster');
55+
export const allocateNodesToJobUpdate = defineUpdate<string[], [AllocateNodesToJobInput]>('allocateNodesToJob');
56+
export const deleteJobUpdate = defineUpdate<void, [DeleteJobInput]>('deleteJob');
57+
const getClusterStatusQuery = defineQuery<{}>('getClusterStatus');
58+
59+
// Activities
60+
const { allocateNodesToJob, deallocateNodesForJob, findBadNodes } = proxyActivities<typeof activities>({
61+
startToCloseTimeout: '1 minute',
62+
});
63+
64+
export async function clusterManagerWorkflow(input: ClusterManagerWorkflowInput) {
65+
let state = {
66+
clusterStarted: false,
67+
clusterShutdown: false,
68+
nodes: {} as Record<string, string | null>,
69+
jobsAdded: new Set<string>(),
70+
maxAssignedNodes: 0,
71+
};
72+
73+
// Signal handlers
74+
setHandler(startClusterSignal, () => {
75+
state.clusterStarted = true;
76+
for (let i = 0; i < 25; i++) {
77+
state.nodes[i.toString()] = null;
78+
}
79+
});
80+
81+
setHandler(shutdownClusterSignal, () => {
82+
state.clusterShutdown = true;
83+
});
84+
85+
setHandler(allocateNodesToJobUpdate, async (input: AllocateNodesToJobInput): Promise<string[]> => {
86+
if (!state.clusterStarted || state.clusterShutdown) {
87+
throw new Error('Cluster is not in a valid state for node allocation');
88+
}
89+
// Allocate nodes to job logic
90+
return [];
91+
});
92+
93+
setHandler(deleteJobUpdate, async (input: DeleteJobInput) => {
94+
if (!state.clusterStarted || state.clusterShutdown) {
95+
throw new Error('Cluster is not in a valid state for node deallocation');
96+
}
97+
// Deallocate nodes from job logic
98+
});
99+
100+
// Query handler
101+
setHandler(getClusterStatusQuery, () => {
102+
return {
103+
clusterStarted: state.clusterStarted,
104+
clusterShutdown: state.clusterShutdown,
105+
numNodes: Object.keys(state.nodes).length,
106+
numAssignedNodes: Object.values(state.nodes).filter((n) => n !== null).length,
107+
};
108+
});
109+
110+
// Main workflow logic
111+
await condition(() => state.clusterStarted, 'Waiting for cluster to start');
112+
// Perform operations while cluster is active
113+
while (!state.clusterShutdown) {
114+
// Example: perform periodic health checks
115+
await sleep(60000); // Sleep for 60 seconds
116+
}
117+
118+
// Return workflow result
119+
return {
120+
maxAssignedNodes: state.maxAssignedNodes,
121+
numCurrentlyAssignedNodes: Object.values(state.nodes).filter((n) => n !== null).length,
122+
numBadNodes: Object.values(state.nodes).filter((n) => n === 'BAD').length,
123+
};
124+
}

0 commit comments

Comments
 (0)