-
Notifications
You must be signed in to change notification settings - Fork 5
Add durable orchestration and entity examples #14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 23 commits
bc26cc7
fb8adb2
995c3a5
76cf4de
bbd5f13
67aa6bf
7908129
5f11b15
5e988d3
2f6db2a
501ac69
12405cc
f038144
948b5ff
8b400f5
7ca8192
418414e
b9c1f5f
2438a1f
2bc476a
2f8c730
af966ae
4ef5943
df691cb
d51d5f1
63ce7bb
8040c03
d5a55e3
ba56c7b
a5f1913
695b94b
86c56b5
bcdcb8a
cf0dc35
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { HttpRequest, InvocationContext, output, trigger } from '@azure/functions'; | ||
import * as df from 'durable-functions'; | ||
import { DurableClientHandler, EntityHandler } from 'durable-functions'; | ||
|
||
// Replace with your own Durable entity name | ||
const entityName = 'Counter'; | ||
|
||
const clientHandler: DurableClientHandler = async (_context: InvocationContext, req: HttpRequest, client) => { | ||
const id: string = req.params.id; | ||
const entityId = new df.EntityId(entityName, id); | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just realized: there's only 1 type of DF input bindings: the With that in mind, do we really need this second parameter? Can we not just call There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Sadly, yes. Under the hood, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This would be another advantage of something like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see. At this time, this is my biggest pain point with the new programming model. Moving forward, I would like for us to prioritize removing this boilerplate, as it is rather clunky and DF apps always need a client. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree with this 100%. But I think we agreed that that shouldn't be in this first iteration. Let me create an issue for this on the Durable SDK to track this so we don't block this PR. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Ftr, the new model could do the same thing where it loops over the context to find the durable client. The library package might not allow you to loop over bindings right now, but we can always change it. That may be helpful outside of durable as well, which you should always keep an eye out for. If we can come up with a fancy new design to improve on the client experience, that's great - but in the interest of time we should keep the "match the old model" option on the table. |
||
if (req.method === 'POST') { | ||
// increment value | ||
await client.signalEntity(entityId, 'add', 1); | ||
} else { | ||
// read current state of entity | ||
const stateResponse = await client.readEntityState(entityId); | ||
return { | ||
body: stateResponse.entityState, | ||
}; | ||
} | ||
}; | ||
df.client('durableEntityStart1', trigger.http({ route: 'entity/{id}' }), output.http({}), clientHandler); | ||
|
||
const entityHandler: EntityHandler<number> = (context) => { | ||
const currentValue: number = context.df.getState(() => 0); | ||
switch (context.df.operationName) { | ||
case 'add': | ||
const amount: number = context.df.getInput(); | ||
context.df.setState(currentValue + amount); | ||
break; | ||
case 'reset': | ||
hossam-nasr marked this conversation as resolved.
Show resolved
Hide resolved
|
||
context.df.setState(0); | ||
break; | ||
case 'get': | ||
context.df.return(currentValue); | ||
break; | ||
} | ||
}; | ||
df.entity(entityName, entityHandler); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { HttpRequest, InvocationContext, output, trigger } from '@azure/functions'; | ||
import * as df from 'durable-functions'; | ||
import { ActivityHandler, DurableClientHandler, OrchestrationHandler } from 'durable-functions'; | ||
|
||
// Replace with the name of your Durable Functions Activity | ||
const activityName = 'hello2'; | ||
|
||
const orchestrator: OrchestrationHandler = function* (context) { | ||
const outputs = []; | ||
outputs.push(yield context.df.callActivity(activityName, 'Tokyo')); | ||
outputs.push(yield context.df.callActivity(activityName, 'Seattle')); | ||
outputs.push(yield context.df.callActivity(activityName, 'Cairo')); | ||
|
||
return outputs; | ||
}; | ||
df.orchestration('durableOrchestrator2', orchestrator); | ||
|
||
const helloActivity: ActivityHandler<string> = (_context: InvocationContext, input: string) => { | ||
return `Hello, ${input}`; | ||
}; | ||
df.activityComplex<string>(activityName, { | ||
extraInputs: [], // could be used to add extra inputs | ||
extraOutputs: [], // could be used to add extra outputs | ||
handler: helloActivity, | ||
}); | ||
|
||
const clientHandler: DurableClientHandler = async (context: InvocationContext, request: HttpRequest, client) => { | ||
const instanceId = await client.startNew(request.params.orchestratorName, undefined, request.text()); | ||
context.log(`Started orchestration with ID = '${instanceId}'.`); | ||
return client.createCheckStatusResponse(request, instanceId); | ||
}; | ||
|
||
df.clientComplex('durableOrchestrationStart2', { | ||
trigger: trigger.http({ | ||
route: 'orchestrators/{orchestratorName}', | ||
}), | ||
return: output.http({}), | ||
extraInputs: [], // could be used to add extra inputs | ||
extraOutputs: [], // could be used to add extra outputs | ||
handler: clientHandler, | ||
}); | ||
hossam-nasr marked this conversation as resolved.
Show resolved
Hide resolved
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { HttpRequest, InvocationContext } from '@azure/functions'; | ||
import * as df from 'durable-functions'; | ||
import { ActivityHandler, DurableClientHandler, OrchestrationHandler } from 'durable-functions'; | ||
|
||
// Replace with the name of your Durable Functions Activity | ||
const activityName = 'hello'; | ||
|
||
const orchestrator: OrchestrationHandler = function* (context) { | ||
const outputs = []; | ||
outputs.push(yield context.df.callActivity(activityName, 'Tokyo')); | ||
outputs.push(yield context.df.callActivity(activityName, 'Seattle')); | ||
outputs.push(yield context.df.callActivity(activityName, 'Cairo')); | ||
|
||
return outputs; | ||
}; | ||
df.orchestration('durableOrchestrator1', orchestrator); | ||
|
||
const helloActivity: ActivityHandler<string> = (_context: InvocationContext, input: string) => { | ||
hossam-nasr marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return `Hello, ${input}`; | ||
}; | ||
df.activity<string>(activityName, helloActivity); | ||
|
||
const clientHandler: DurableClientHandler = async (context: InvocationContext, request: HttpRequest, client) => { | ||
const instanceId = await client.startNew(request.query.get('orchestratorName'), undefined, request.text()); | ||
context.log(`Started orchestration with ID = '${instanceId}'.`); | ||
return client.createCheckStatusResponse(request, instanceId); | ||
}; | ||
df.httpClient('durableOrchestrationStart1', clientHandler); |
Uh oh!
There was an error while loading. Please reload this page.