Skip to content

Commit 5d37c9d

Browse files
committed
fix: warn when ad-hoc webhooks drop unsupported Webhook fields
1 parent cfff7bb commit 5d37c9d

2 files changed

Lines changed: 59 additions & 4 deletions

File tree

src/apify/_webhook.py

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from crawlee._utils.urls import validate_http_url
88

99
from apify._utils import docs_group
10+
from apify.log import logger
1011

1112
if TYPE_CHECKING:
1213
from apify_client._literals import WebhookEventType
@@ -19,6 +20,9 @@ class Webhook:
1920
2021
The same instance can be passed as an ad-hoc webhook to `Actor.start()` / `Actor.call()` or as a persistent
2122
webhook to `Actor.add_webhook()` (the `condition.actor_run_id` is set automatically to the current run).
23+
24+
Ad-hoc webhooks support only `event_types`, `request_url`, `payload_template` and `headers_template`; the
25+
remaining fields apply only to `Actor.add_webhook()` and are ignored (with a warning) otherwise.
2226
"""
2327

2428
event_types: list[WebhookEventType]
@@ -34,23 +38,41 @@ class Webhook:
3438
"""Template for the HTTP headers sent by the webhook."""
3539

3640
idempotency_key: str | None = None
37-
"""Key that prevents creating duplicate webhooks."""
41+
"""Key that prevents creating duplicate webhooks. Only applies to `Actor.add_webhook()`."""
3842

3943
ignore_ssl_errors: bool | None = None
40-
"""Whether to ignore SSL errors when sending the request."""
44+
"""Whether to ignore SSL errors when sending the request. Only applies to `Actor.add_webhook()`."""
4145

4246
do_not_retry: bool | None = None
43-
"""Whether to skip retrying the request on failure."""
47+
"""Whether to skip retrying the request on failure. Only applies to `Actor.add_webhook()`."""
4448

4549
def __post_init__(self) -> None:
4650
# Fail fast on a malformed URL at construction time instead of deferring the error to the API call.
4751
validate_http_url(self.request_url)
4852

4953

5054
def to_client_representations(webhooks: list[Webhook] | None) -> list[WebhookRepresentation] | None:
51-
"""Project SDK webhooks to the minimal ad-hoc representation accepted by the client's `start()` / `call()`."""
55+
"""Project SDK webhooks to the minimal ad-hoc representation accepted by the client's `start()` / `call()`.
56+
57+
Fields not supported by ad-hoc webhooks (`idempotency_key`, `ignore_ssl_errors`, `do_not_retry`) are dropped
58+
with a warning.
59+
"""
5260
if not webhooks:
5361
return None
62+
63+
for webhook in webhooks:
64+
dropped = [
65+
field
66+
for field in ('idempotency_key', 'ignore_ssl_errors', 'do_not_retry')
67+
if getattr(webhook, field) is not None
68+
]
69+
if dropped:
70+
fields = ', '.join(f'`{field}`' for field in dropped)
71+
logger.warning(
72+
f'Ad-hoc webhooks do not support {fields}; the field(s) will be ignored. '
73+
f'Use `Actor.add_webhook()` to create a webhook with them.'
74+
)
75+
5476
return [
5577
WebhookRepresentation(
5678
event_types=w.event_types,

tests/unit/actor/test_actor_helpers.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,39 @@ async def test_remote_method_with_webhooks(
251251
assert kwargs['webhooks'] is not None
252252

253253

254+
@pytest.mark.parametrize(('client_resource', 'client_method', 'actor_method_name', 'entity_id'), _ACTOR_REMOTE_METHODS)
255+
async def test_remote_method_warns_on_unsupported_webhook_fields(
256+
apify_client_async_patcher: ApifyClientAsyncPatcher,
257+
fake_actor_run: Run,
258+
client_resource: str,
259+
client_method: str,
260+
actor_method_name: str,
261+
entity_id: str,
262+
caplog: pytest.LogCaptureFixture,
263+
) -> None:
264+
"""Test that start/call/call_task warn about `Webhook` fields not supported by ad-hoc webhooks."""
265+
apify_client_async_patcher.patch(client_resource, client_method, return_value=fake_actor_run)
266+
caplog.set_level('WARNING')
267+
268+
async with Actor:
269+
actor_method = getattr(Actor, actor_method_name)
270+
await actor_method(
271+
entity_id,
272+
webhooks=[
273+
Webhook(
274+
event_types=['ACTOR.RUN.SUCCEEDED'],
275+
request_url='https://example.com',
276+
idempotency_key='some-key',
277+
do_not_retry=True,
278+
)
279+
],
280+
)
281+
282+
matching = [record for record in caplog.records if 'Ad-hoc webhooks do not support' in record.message]
283+
assert len(matching) == 1
284+
assert '`idempotency_key`, `do_not_retry`' in matching[0].message
285+
286+
254287
@pytest.mark.parametrize(('client_resource', 'client_method', 'actor_method_name', 'entity_id'), _ACTOR_REMOTE_METHODS)
255288
async def test_remote_method_with_timedelta_timeout(
256289
apify_client_async_patcher: ApifyClientAsyncPatcher,

0 commit comments

Comments
 (0)