Skip to content

Commit 62a6034

Browse files
authored
Merge pull request #247 from Azure/dev
Promote dev to main for 1.4.6 release
2 parents 685da1f + f005d48 commit 62a6034

File tree

4 files changed

+106
-4
lines changed

4 files changed

+106
-4
lines changed

package-lock.json

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "durable-functions",
3-
"version": "1.4.5",
3+
"version": "1.4.6",
44
"description": "Durable Functions library for Node.js Azure Functions",
55
"license": "MIT",
66
"repository": {

src/durableorchestrationclient.ts

+45-2
Original file line numberDiff line numberDiff line change
@@ -870,7 +870,23 @@ export class DurableOrchestrationClient {
870870
return origins;
871871
}
872872

873-
private async getStatusInternal(options: GetStatusOptions): Promise<AxiosResponse> {
873+
/**
874+
* Internal method that gets the status of all orchestration instances that
875+
* match the specified conditions. It handles pagination automatically by
876+
* calling itself recursively until no more continuation tokens are found.
877+
* @param options Return orchestration instances which were created
878+
* after this Date.
879+
* @param [continuationToken] Continuation token corresponding to the
880+
* `x-ms-continuation-token` header, for getting the next batch
881+
* of results. Used for recursion.
882+
* @param [prevData] Results of a previous request, used internally
883+
* to aggregate results during recursion.
884+
*/
885+
private async getStatusInternal(
886+
options: GetStatusOptions,
887+
continuationToken?: string,
888+
prevData?: unknown[]
889+
): Promise<AxiosResponse> {
874890
let requestUrl: string;
875891
if (this.clientData.rpcBaseUrl) {
876892
// Fast local RPC path
@@ -958,7 +974,34 @@ export class DurableOrchestrationClient {
958974
}
959975
}
960976

961-
return this.axiosInstance.get(requestUrl);
977+
// If a continuation token is provided, we add it to the request's header
978+
let axiosConfig = undefined;
979+
if (continuationToken) {
980+
axiosConfig = {
981+
headers: {
982+
"x-ms-continuation-token": continuationToken,
983+
},
984+
};
985+
}
986+
987+
// We call the getStatus endpoint and construct a promise callback to handle the recursion
988+
// This assumes that, so long as continuation tokens are found, that the http response status
989+
// can be safely ignored (either 200 or 202).
990+
const response = this.axiosInstance.get(requestUrl, axiosConfig).then((httpResponse) => {
991+
// Aggregate results so far
992+
const headers = httpResponse.headers;
993+
if (prevData) {
994+
httpResponse.data = prevData.concat(httpResponse.data);
995+
}
996+
// If a new continuation token is found, recurse. Otherwise, return the results
997+
const token = headers["x-ms-continuation-token"];
998+
if (token) {
999+
return this.getStatusInternal(options, token, httpResponse.data);
1000+
}
1001+
return httpResponse;
1002+
});
1003+
1004+
return response;
9621005
}
9631006

9641007
private createGenericError(response: AxiosResponse<any>): Error {

test/unit/durableclient-spec.ts

+59
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import nock = require("nock");
55
import url = require("url");
66
import {
77
DurableOrchestrationClient,
8+
DurableOrchestrationStatus,
89
EntityId,
910
EntityStateResponse,
1011
HttpManagementPayload,
@@ -244,6 +245,64 @@ describe("Durable client RPC endpoint", () => {
244245
expect(scope.isDone()).to.be.equal(true);
245246
expect(result).to.be.an("array");
246247
});
248+
249+
it("uses continuation header", async () => {
250+
const input = JSON.parse(durableClientBindingInputJson) as OrchestrationClientInputData;
251+
const client = new DurableOrchestrationClient(input);
252+
253+
// The getStatusBy() method should do a GET to http://127.0.0.1:17071/durabletask/instances/?createdTimeFrom=2020-01-01T00:00:00Z&createdTimeTo=2020-01-01T23:59:59Z&runtimeStatus=Pending,Running,Completed,Terminated,Failed
254+
const expectedUrl = new URL(`${testRpcOrigin}/durabletask/instances/`);
255+
const createdTimeFrom = "2020-01-01T00:00:00.000Z";
256+
const createdTimeTo = "2020-01-01T23:59:59.000Z";
257+
const runtimeStatus = "Pending,Running,Completed,Terminated,Failed";
258+
259+
// create dummy orchestration status for response
260+
const dummyDate = new Date();
261+
const dummyStatus = new DurableOrchestrationStatus(
262+
"dummyOrchestrationStatus",
263+
"123456",
264+
dummyDate,
265+
dummyDate,
266+
"myInput",
267+
"myOutput",
268+
OrchestrationRuntimeStatus.Completed
269+
);
270+
const dummyStatusJSON = JSON.stringify(dummyStatus);
271+
272+
const scopeWithTokenResponse = nock(expectedUrl.origin)
273+
.get(expectedUrl.pathname)
274+
.query({ createdTimeFrom, createdTimeTo, runtimeStatus })
275+
.reply(200, [dummyStatusJSON, dummyStatusJSON], {
276+
"x-ms-continuation-token": "myToken",
277+
});
278+
279+
const scopeNoTokenResponse = nock(expectedUrl.origin, {
280+
reqheaders: {
281+
"x-ms-continuation-token": "myToken",
282+
},
283+
})
284+
.get(expectedUrl.pathname)
285+
.query({ createdTimeFrom, createdTimeTo, runtimeStatus })
286+
.reply(200, [dummyStatusJSON]);
287+
288+
const statusList = runtimeStatus
289+
.split(",")
290+
.map(
291+
(status) =>
292+
OrchestrationRuntimeStatus[
293+
status as keyof typeof OrchestrationRuntimeStatus
294+
]
295+
);
296+
const result = await client.getStatusBy(
297+
new Date(createdTimeFrom),
298+
new Date(createdTimeTo),
299+
statusList
300+
);
301+
expect(scopeWithTokenResponse.isDone()).to.be.equal(true);
302+
expect(scopeNoTokenResponse.isDone()).to.be.equal(true);
303+
expect(result).to.be.an("array");
304+
expect(result).to.be.of.length(3);
305+
});
247306
});
248307

249308
describe("terminate()", () => {

0 commit comments

Comments
 (0)