Skip to content

Commit eabdcbd

Browse files
committed
docs(scrapy): document JSON serialization breaking change in v4 upgrading guide
1 parent 31c05d7 commit eabdcbd

1 file changed

Lines changed: 33 additions & 0 deletions

File tree

docs/04_upgrading/upgrading_to_v4.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,3 +198,36 @@ await client.run('my-run').charge('my-event', count=5)
198198
### Async `iterate_*` are no longer coroutine functions
199199

200200
`DatasetClientAsync.iterate_items()` and `KeyValueStoreClientAsync.iterate_keys()` are now plain `def` functions returning `AsyncIterator[T]`. Consumer code (`async for ...`) is unchanged; if you annotate the call's return value, change `AsyncGenerator[T, None]` to `AsyncIterator[T]`.
201+
202+
## Scrapy requests and HTTP cache stored as JSON
203+
204+
This applies only if you use the Scrapy integration (`apify[scrapy]`).
205+
206+
The integration now serializes data as JSON instead of pickle. `ApifyScheduler` stores Scrapy requests in the Apify request queue (under `user_data['scrapy_request']`), and `ApifyCacheStorage` stores HTTP cache entries in the key-value store. Both now hold JSON. Unlike pickle, JSON stays stable across Python and library versions.
207+
208+
### Persisted data from before the upgrade is not read back
209+
210+
Data written by an older SDK uses the pickle format, which v4 does not load. The two storages handle this differently:
211+
212+
- HTTP cache: a legacy entry is treated as a cache miss. Scrapy re-fetches the page and re-stores it as JSON, so the cache heals itself. No action is needed.
213+
- Request queue: a request stored by an older SDK cannot be reconstructed, so it is skipped and the failure is logged. This matters only when pre-upgrade requests are still in the queue, for example after a run is migrated or restarted, or when you reuse a named request queue. A fresh run is not affected.
214+
215+
### `meta` and `cb_kwargs` must be JSON-serializable
216+
217+
Pickle could store arbitrary Python objects. JSON cannot, so the values in a request's `meta` and `cb_kwargs` are now subject to JSON's type system:
218+
219+
- A `tuple` comes back as a `list`.
220+
- Non-string `dict` keys come back as strings, so `{1: 'a'}` becomes `{'1': 'a'}`.
221+
- A value JSON cannot represent (`datetime`, `set`, `Decimal`, a custom object) is no longer stored silently. The request is skipped and the failure is logged. Pydantic models are still supported and are dumped with `model_dump()`.
222+
223+
Convert such values to a JSON-friendly form before yielding the request:
224+
225+
```python
226+
from datetime import datetime
227+
228+
# Before (v3): relied on pickle to store the datetime object.
229+
yield scrapy.Request(url, meta={'since': datetime(2024, 1, 1)})
230+
231+
# After (v4): store a JSON-serializable value.
232+
yield scrapy.Request(url, meta={'since': datetime(2024, 1, 1).isoformat()})
233+
```

0 commit comments

Comments
 (0)