Skip to content

Commit

Permalink
feat: Add charge method to the run client for "pay per event" (#304)
Browse files Browse the repository at this point in the history
Resolves apify/apify-core#18593 by adding the
charge endpoint to the run client.

Issue to add docs URL
#305

---------

Co-authored-by: Vlada Dusek <[email protected]>
  • Loading branch information
Jkuzz and vdusek authored Dec 5, 2024
1 parent 272bf5e commit 3bd6bbb
Showing 1 changed file with 76 additions and 0 deletions.
76 changes: 76 additions & 0 deletions src/apify_client/clients/resource_clients/run.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
from __future__ import annotations

import json
import random
import string
import time
from typing import Any

from apify_shared.utils import filter_out_none_values_recursively, ignore_docs, parse_date_fields
Expand Down Expand Up @@ -226,6 +230,42 @@ def log(self: RunClient) -> LogClient:
**self._sub_resource_init_options(resource_path='log'),
)

def charge(
self: RunClient,
event_name: str,
count: int | None = None,
idempotency_key: str | None = None,
) -> dict:
"""Charge for an event of a Pay-Per-Event Actor run.
https://docs.apify.com/api/v2#/reference/actor-runs/charge-run/charge-run
Returns:
dict: Status and message of the charge event.
"""
if not event_name:
raise ValueError('event_name is required for charging an event')

idempotency_key = idempotency_key or (
f'{self.resource_id}-{event_name}-{int(time.time() * 1000)}-{"".join(random.choices(string.ascii_letters + string.digits, k=6))}'
)

response = self.http_client.call(
url=self._url('charge'),
method='POST',
headers={
'idempotency-key': idempotency_key,
'content-type': 'application/json',
},
data=json.dumps(
{
'eventName': event_name,
'count': count or 1,
}
),
)
return parse_date_fields(pluck_data(response.json()))


class RunClientAsync(ActorJobBaseClientAsync):
"""Async sub-client for manipulating a single Actor run."""
Expand Down Expand Up @@ -440,3 +480,39 @@ def log(self: RunClientAsync) -> LogClientAsync:
return LogClientAsync(
**self._sub_resource_init_options(resource_path='log'),
)

async def charge(
self: RunClientAsync,
event_name: str,
count: int | None = None,
idempotency_key: str | None = None,
) -> dict:
"""Charge for an event of a Pay-Per-Event Actor run.
https://docs.apify.com/api/v2#/reference/actor-runs/charge-run/charge-run
Returns:
dict: Status and message of the charge event.
"""
if not event_name:
raise ValueError('event_name is required for charging an event')

idempotency_key = idempotency_key or (
f'{self.resource_id}-{event_name}-{int(time.time() * 1000)}-{"".join(random.choices(string.ascii_letters + string.digits, k=6))}'
)

response = await self.http_client.call(
url=self._url('charge'),
method='POST',
headers={
'idempotency-key': idempotency_key,
'content-type': 'application/json',
},
data=json.dumps(
{
'eventName': event_name,
'count': count or 1,
}
),
)
return parse_date_fields(pluck_data(response.json()))

0 comments on commit 3bd6bbb

Please sign in to comment.