Skip to content

Commit 9442187

Browse files
authored
feat: add support for maxItems in run options (#330)
This adds support for optional `maxItems` param to `start` and `call` methods on actors and tasks. This param will be used by pay per result actors to limit max items that will be charged to customer. Should be merged after apify/apify-worker#734 is released.
1 parent 4ac1ba4 commit 9442187

4 files changed

Lines changed: 97 additions & 2 deletions

File tree

src/resource_clients/actor.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,16 +66,18 @@ export class ActorClient extends ResourceClient {
6666
timeout: ow.optional.number,
6767
waitForFinish: ow.optional.number,
6868
webhooks: ow.optional.array.ofType(ow.object),
69+
maxItems: ow.optional.number.not.negative,
6970
}));
7071

71-
const { waitForFinish, timeout, memory, build } = options;
72+
const { waitForFinish, timeout, memory, build, maxItems } = options;
7273

7374
const params = {
7475
waitForFinish,
7576
timeout,
7677
memory,
7778
build,
7879
webhooks: stringifyWebhooksToBase64(options.webhooks),
80+
maxItems,
7981
};
8082

8183
const request: AxiosRequestConfig = {
@@ -115,6 +117,7 @@ export class ActorClient extends ResourceClient {
115117
timeout: ow.optional.number.not.negative,
116118
waitSecs: ow.optional.number.not.negative,
117119
webhooks: ow.optional.array.ofType(ow.object),
120+
maxItems: ow.optional.number.not.negative,
118121
}));
119122

120123
const { waitSecs, ...startOptions } = options;
@@ -324,6 +327,13 @@ export interface ActorStartOptions {
324327
* [ad hook webhooks documentation](https://docs.apify.com/webhooks/ad-hoc-webhooks) for detailed description.
325328
*/
326329
webhooks?: readonly WebhookUpdateData[];
330+
331+
/**
332+
* Specifies maximum number of items that the actor run should return.
333+
* This is used by pay per result actors to limit the maximum number of results that will be charged to customer.
334+
* Value can be accessed in actor run using `APIFY_ACTOR_MAX_ITEMS` environment variable.
335+
*/
336+
maxItems?: number;
327337
}
328338

329339
export interface ActorCallOptions extends Omit<ActorStartOptions, 'waitForFinish'> {

src/resource_clients/task.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,16 +63,18 @@ export class TaskClient extends ResourceClient {
6363
timeout: ow.optional.number,
6464
waitForFinish: ow.optional.number,
6565
webhooks: ow.optional.array.ofType(ow.object),
66+
maxItems: ow.optional.number.not.negative,
6667
}));
6768

68-
const { waitForFinish, timeout, memory, build } = options;
69+
const { waitForFinish, timeout, memory, build, maxItems } = options;
6970

7071
const params = {
7172
waitForFinish,
7273
timeout,
7374
memory,
7475
build,
7576
webhooks: stringifyWebhooksToBase64(options.webhooks),
77+
maxItems,
7678
};
7779

7880
const request: ApifyRequestConfig = {
@@ -105,6 +107,7 @@ export class TaskClient extends ResourceClient {
105107
timeout: ow.optional.number.not.negative,
106108
waitSecs: ow.optional.number.not.negative,
107109
webhooks: ow.optional.array.ofType(ow.object),
110+
maxItems: ow.optional.number.not.negative,
108111
}));
109112

110113
const { waitSecs, ...startOptions } = options;

test/actors.test.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,18 @@ describe('Actor methods', () => {
197197
validateRequest({ webhooks: stringifyWebhooksToBase64(webhooks) }, { actorId });
198198
});
199199

200+
test('start() with max items works', async () => {
201+
const actorId = 'some-id';
202+
203+
const res = await client.actor(actorId).start(undefined, { maxItems: 100 });
204+
expect(res.id).toEqual('run-actor');
205+
validateRequest({ maxItems: 100 }, { actorId });
206+
207+
const browserRes = await page.evaluate((id, opts) => client.actor(id).start(undefined, opts), actorId, { maxItems: 100 });
208+
expect(browserRes).toEqual(res);
209+
validateRequest({ maxItems: 100 }, { actorId });
210+
});
211+
200212
test('call() works', async () => {
201213
const actorId = 'some-id';
202214
const contentType = 'application/x-www-form-urlencoded';
@@ -244,6 +256,32 @@ describe('Actor methods', () => {
244256
}, { actorId }, { some: 'body' }, { 'content-type': contentType });
245257
});
246258

259+
test('call() works with maxItems', async () => {
260+
const actorId = 'some-id';
261+
const runId = 'started-run-id';
262+
const data = { id: runId, actId: actorId, status: 'SUCCEEDED' };
263+
const body = { data };
264+
const waitSecs = 1;
265+
const maxItems = 100;
266+
267+
mockServer.setResponse({ body });
268+
const res = await client.actor(actorId).call(undefined, { waitSecs, maxItems });
269+
270+
expect(res).toEqual(data);
271+
validateRequest({ waitForFinish: waitSecs }, { runId });
272+
validateRequest({ maxItems }, { actorId });
273+
274+
const callBrowserRes = await page.evaluate(
275+
(id, i, opts) => client.actor(id).call(i, opts), actorId, undefined, {
276+
waitSecs,
277+
maxItems,
278+
},
279+
);
280+
expect(callBrowserRes).toEqual(res);
281+
validateRequest({ waitForFinish: waitSecs }, { runId });
282+
validateRequest({ maxItems }, { actorId });
283+
});
284+
247285
test('build() works', async () => {
248286
const actorId = 'some-id';
249287

test/tasks.test.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,17 @@ describe('Task methods', () => {
249249
validateRequest(query, { taskId });
250250
});
251251

252+
test('start() works with maxItems', async () => {
253+
const taskId = 'some-id';
254+
const res = await client.task(taskId).start(undefined, { maxItems: 100 });
255+
expect(res.id).toEqual('run-task');
256+
validateRequest({ maxItems: 100 }, { taskId });
257+
258+
const browserRes = await page.evaluate((id, opts) => client.task(id).start(undefined, opts), taskId, { maxItems: 100 });
259+
expect(browserRes).toEqual(res);
260+
validateRequest({ maxItems: 100 }, { taskId });
261+
});
262+
252263
test('call() works', async () => {
253264
const taskId = 'some-task-id';
254265
const input = { some: 'body' };
@@ -297,6 +308,39 @@ describe('Task methods', () => {
297308
}, { taskId }, { some: 'body' });
298309
});
299310

311+
test('call() works with maxItems', async () => {
312+
const taskId = 'some-task-id';
313+
const actId = 'started-actor-id';
314+
const runId = 'started-run-id';
315+
const data = { id: runId, actId, status: 'SUCCEEDED' };
316+
const body = { data };
317+
const waitSecs = 1;
318+
const maxItems = 100;
319+
320+
const query = { maxItems };
321+
322+
mockServer.setResponse({ body });
323+
const res = await client.task(taskId).call(undefined, {
324+
waitSecs,
325+
maxItems,
326+
});
327+
expect(res).toEqual(data);
328+
329+
expect(res).toEqual(data);
330+
validateRequest({ waitForFinish: waitSecs }, { runId });
331+
validateRequest(query, { taskId });
332+
333+
const callBrowserRes = await page.evaluate(
334+
(id, i, opts) => client.task(id).call(i, opts), taskId, undefined, {
335+
waitSecs,
336+
maxItems,
337+
},
338+
);
339+
expect(callBrowserRes).toEqual(res);
340+
validateRequest({ waitForFinish: waitSecs }, { runId });
341+
validateRequest({ maxItems }, { taskId });
342+
});
343+
300344
test('webhooks().list() works', async () => {
301345
const taskId = 'some-task-id';
302346
const query = {

0 commit comments

Comments
 (0)