Skip to content

Commit b652e57

Browse files
committed
intial upgrade guide
1 parent f80d600 commit b652e57

File tree

3 files changed

+374
-0
lines changed

3 files changed

+374
-0
lines changed

articles/azure-functions/durable/TOC.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@
5858
href: durable-functions-phone-verification.md
5959
- name: Publish to Event Grid
6060
href: durable-functions-event-publishing.md
61+
- name: Upgrade to Node.js model v4
62+
href: durable-functions-node-model-upgrade.md
6163
- name: Samples
6264
items:
6365
- name: Code samples
Lines changed: 364 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,364 @@
1+
---
2+
title: Upgrade your Durable Functions app to version 4 of the Node.js programming model
3+
description: This article shows you how to upgrade your existing Durable Functions apps running on v3 of the Node.js programming model to v4.
4+
author: hossam-nasr
5+
ms.service: azure-functions
6+
ms.date: 04/06/2023
7+
ms.devlang: javascript, typescript
8+
ms.author: azfuncdf
9+
ms.topic: how-to
10+
zone_pivot_groups: programming-languages-set-functions-nodejs
11+
---
12+
13+
# Upgrade your Durable Functions app to version 4 of the Node.js programming model
14+
15+
>[!NOTE]
16+
> Version 4 of the Node.js programming model is currently in public preview.
17+
18+
This article provides a guide to upgrade your existing Durable Functions app to newly-released version 4 of the Node.js programming model for Azure Functions from the existing version 3. If you are instead interested in creating a brand new v4 app, follow the Visual Studio Code quickstarts for [JavaScript](./quickstart-js-vscode.md?pivots=nodejs-model-v4) and [TypeScript](./quickstart-ts-vscode.md?pivots=nodejs-model-v4). This article uses "TIP" sections to highlight the most important concrete actions you should take to upgrade your app. Before following this guide, make sure you follow the general [version 4 upgrade guide](../functions-node-upgrade-v4.md). You can also learn more about the new v4 programming model through the [Node.js developer reference](../functions-reference-node.md?pivots=nodejs-model-v4).
19+
20+
>[!TIP]
21+
> Before following this guide, make sure you follow the general [version 4 upgrade guide](../functions-node-upgrade-v4.md).
22+
23+
## Prerequisites
24+
25+
Before following this guide, make sure you follow these steps first:
26+
27+
- Install have [Node.js](https://nodejs.org/en/download/releases) version 18.x+.
28+
- Install [TypeScript](https://www.typescriptlang.org/) version 4.x+.
29+
- Run your app on [Azure Functions Runtime](https://learn.microsoft.com/azure/azure-functions/functions-versions?tabs=v4&pivots=programming-language-javascript) version 4.16.5+.
30+
- Install [Azure Functions Core Tools](https://learn.microsoft.com/azure/azure-functions/functions-run-local?tabs=v4) version 4.0.5095+.
31+
- Follow the general [Azure Functions Node.js programming model v4 upgrade guide](../functions-node-upgrade-v4.md).
32+
33+
## Upgrade durable-functions npm package
34+
35+
The v4 programming model is supported by the v3.x of the `durable-functions` npm package. In v3, you likely had `durable-functions` v2.x listed in your dependencies. Make sure to update to the (currently in preview) v3.x of the package.
36+
37+
>[!TIP]
38+
> Upgrade to the preview v3.x of the `durable-functions` npm package. You can do this with the following command:
39+
>
40+
> ```bash
41+
> npm install durable-functions@preview
42+
> ```
43+
44+
## Register your durable functions in code
45+
46+
In the v4 programming model, `function.json` files are a thing of the past! In v3, you would have to register your orchestration, entity, and activity triggers in a `function.json` file, and export your function implementation using `orchestrator()` or `entity()` APIs from the `durable-functions` package. With v3.x of `durable-functions`, APIs were added to the `app` namespace on the root of the package to allow you to register your durable orchestrations, entities, and activities directly in code! Find the below code snippets for examples.
47+
48+
#### Migrating an orchestration
49+
50+
:::zone pivot="programming-language-javascript"
51+
# [v4 model](#tab/v4)
52+
53+
```JS
54+
const df = require('durable-functions');
55+
56+
const activityName = 'helloActivity';
57+
58+
df.app.orchestration('durableOrchestrator', function* (context) {
59+
const outputs = [];
60+
outputs.push(yield context.df.callActivity(activityName, 'Tokyo'));
61+
outputs.push(yield context.df.callActivity(activityName, 'Seattle'));
62+
outputs.push(yield context.df.callActivity(activityName, 'Cairo'));
63+
64+
return outputs;
65+
});
66+
```
67+
68+
# [v3 model](#tab/v3)
69+
70+
```JS
71+
const df = require("durable-functions");
72+
73+
const activityName = "hello"
74+
75+
module.exports = df.orchestrator(function* (context) {
76+
const outputs = [];
77+
outputs.push(yield context.df.callActivity(activityName, "Tokyo"));
78+
outputs.push(yield context.df.callActivity(activityName, "Seattle"));
79+
outputs.push(yield context.df.callActivity(activityName, "London"));
80+
81+
return outputs;
82+
});
83+
```
84+
85+
```json
86+
{
87+
"bindings": [
88+
{
89+
"name": "context",
90+
"type": "orchestrationTrigger",
91+
"direction": "in"
92+
}
93+
]
94+
}
95+
```
96+
97+
---
98+
:::zone-end
99+
100+
:::zone pivot="programming-language-typescript"
101+
# [v4 model](#tab/v4)
102+
103+
```typescript
104+
import * as df from 'durable-functions';
105+
import { OrchestrationContext, OrchestrationHandler } from 'durable-functions';
106+
107+
const activityName = 'hello';
108+
109+
const durableHello1Orchestrator: OrchestrationHandler = function* (context: OrchestrationContext) {
110+
const outputs = [];
111+
outputs.push(yield context.df.callActivity(activityName, 'Tokyo'));
112+
outputs.push(yield context.df.callActivity(activityName, 'Seattle'));
113+
outputs.push(yield context.df.callActivity(activityName, 'Cairo'));
114+
115+
return outputs;
116+
};
117+
df.app.orchestration('durableOrchestrator', durableHello1Orchestrator);
118+
```
119+
120+
# [v3 model](#tab/v3)
121+
122+
```typescript
123+
import * as df from "durable-functions"
124+
125+
const activityName = "hello"
126+
127+
const orchestrator = df.orchestrator(function* (context) {
128+
const outputs = [];
129+
outputs.push(yield context.df.callActivity(activityName, "Tokyo"));
130+
outputs.push(yield context.df.callActivity(activityName, "Seattle"));
131+
outputs.push(yield context.df.callActivity(activityName, "London"));
132+
133+
return outputs;
134+
});
135+
136+
export default orchestrator;
137+
```
138+
139+
```json
140+
{
141+
"bindings": [
142+
{
143+
"name": "context",
144+
"type": "orchestrationTrigger",
145+
"direction": "in"
146+
}
147+
],
148+
"scriptFile": "../dist/durableOrchestrator/index.js"
149+
}
150+
```
151+
152+
---
153+
:::zone-end
154+
155+
156+
#### Migrating an entity
157+
158+
:::zone pivot="programming-model-javascript"
159+
160+
# [v4 model](#tab/v4)
161+
162+
```javascript
163+
const df = require('durable-functions');
164+
165+
df.app.entity('Counter', (context) => {
166+
const currentValue = context.df.getState(() => 0);
167+
switch (context.df.operationName) {
168+
case 'add':
169+
const amount = context.df.getInput();
170+
context.df.setState(currentValue + amount);
171+
break;
172+
case 'reset':
173+
context.df.setState(0);
174+
break;
175+
case 'get':
176+
context.df.return(currentValue);
177+
break;
178+
}
179+
});
180+
```
181+
182+
# [v3 model](#tab/v3)
183+
184+
```javascript
185+
const df = require("durable-functions");
186+
187+
module.exports = df.entity(function (context) {
188+
const currentValue = context.df.getState(() => 0);
189+
switch (context.df.operationName) {
190+
case "add":
191+
const amount = context.df.getInput();
192+
context.df.setState(currentValue + amount);
193+
break;
194+
case "reset":
195+
context.df.setState(0);
196+
break;
197+
case "get":
198+
context.df.return(currentValue);
199+
break;
200+
}
201+
});
202+
```
203+
204+
```json
205+
{
206+
"bindings": [
207+
{
208+
"name": "context",
209+
"type": "entityTrigger",
210+
"direction": "in"
211+
}
212+
]
213+
}
214+
```
215+
216+
---
217+
:::zone-end
218+
219+
:::zone pivot="programming-model-typescript"
220+
221+
# [v4 model](#tab/v4)
222+
223+
```typescript
224+
import * as df from 'durable-functions';
225+
import { EntityContext, EntityHandler } from 'durable-functions';
226+
227+
const counterEntity: EntityHandler<number> = (context: EntityContext<number>) => {
228+
const currentValue: number = context.df.getState(() => 0);
229+
switch (context.df.operationName) {
230+
case 'add':
231+
const amount: number = context.df.getInput();
232+
context.df.setState(currentValue + amount);
233+
break;
234+
case 'reset':
235+
context.df.setState(0);
236+
break;
237+
case 'get':
238+
context.df.return(currentValue);
239+
break;
240+
}
241+
};
242+
df.app.entity('Counter', counterEntity);
243+
```
244+
245+
# [v3 model](#tab/v3)
246+
247+
```typescript
248+
import * as df from "durable-functions"
249+
250+
const entity = df.entity(function (context) {
251+
const currentValue = context.df.getState(() => 0) as number;
252+
switch (context.df.operationName) {
253+
case "add":
254+
const amount = context.df.getInput() as number;
255+
context.df.setState(currentValue + amount);
256+
break;
257+
case "reset":
258+
context.df.setState(0);
259+
break;
260+
case "get":
261+
context.df.return(currentValue);
262+
break;
263+
}
264+
});
265+
266+
export default entity;
267+
```
268+
269+
```json
270+
{
271+
"bindings": [
272+
{
273+
"name": "context",
274+
"type": "entityTrigger",
275+
"direction": "in"
276+
}
277+
],
278+
"scriptFile": "../dist/Counter/index.js"
279+
}
280+
```
281+
282+
----
283+
:::zone-end
284+
285+
#### Migrating an activity
286+
287+
:::zone pivot="programming-language-javascript"
288+
289+
# [v4 model](#tab/v4)
290+
291+
```javascript
292+
const df = require('durable-functions');
293+
294+
df.app.activity('hello', {
295+
handler: (input) => {
296+
return `Hello, ${input}`;
297+
},
298+
});
299+
```
300+
301+
# [v3 model](#tab/v3)
302+
303+
```javascript
304+
module.exports = async function (context) {
305+
return `Hello, ${context.bindings.name}!`;
306+
};
307+
```
308+
309+
```json
310+
{
311+
"bindings": [
312+
{
313+
"name": "name",
314+
"type": "activityTrigger",
315+
"direction": "in"
316+
}
317+
]
318+
}
319+
```
320+
321+
---
322+
:::zone-end
323+
324+
:::zone pivot="programming-language-typescript"
325+
# [v4 model](#tab/v4)
326+
327+
```typescript
328+
import * as df from 'durable-functions';
329+
import { ActivityHandler } from "durable-functions";
330+
331+
const helloActivity: ActivityHandler = (input: string): string => {
332+
return `Hello, ${input}`;
333+
};
334+
335+
df.app.activity('hello', { handler: helloActivity });
336+
```
337+
338+
# [v3 model](#tab/v3)
339+
340+
```typescript
341+
import { AzureFunction, Context } from "@azure/functions"
342+
343+
const helloActivity: AzureFunction = async function (context: Context): Promise<string> {
344+
return `Hello, ${context.bindings.name}!`;
345+
};
346+
347+
export default helloActivity;
348+
```
349+
350+
```json
351+
{
352+
"bindings": [
353+
{
354+
"name": "name",
355+
"type": "activityTrigger",
356+
"direction": "in"
357+
}
358+
],
359+
"scriptFile": "../dist/hello/index.js"
360+
}
361+
```
362+
363+
---
364+
:::zone-end

articles/zone-pivot-groups.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,14 @@ groups:
355355
title: TypeScript
356356
- id: programming-language-other
357357
title: Other
358+
- id: programming-languages-set-functions-nodejs
359+
title: Programming languages
360+
prompt: Choose a programming language
361+
pivots:
362+
- id: programming-language-javascript
363+
title: JavaScript
364+
- id: programming-language-typescript
365+
title: TypeScript
358366
- id: development-environment-functions
359367
title: Development environment
360368
prompt: Choose a development environment

0 commit comments

Comments
 (0)