|
9 | 9 |
|
10 | 10 | Tests |
11 | 11 | ----- |
12 | | -1. Non-blocking reads (canary) |
13 | | - A background task ticks every 10 ms while each GET call runs. Measures the |
14 | | - max gap between ticks. A blocking call (e.g. requests instead of aiohttp, |
15 | | - or time.sleep instead of asyncio.sleep) would starve the canary and produce |
16 | | - a gap equal to the full round-trip. Covers: records.list, tables.list, |
17 | | - tables.get, query.sql, query.fetchxml, query.builder. |
18 | | -
|
19 | | -2. Read throughput (sequential vs concurrent) |
20 | | - Runs N reads sequentially then N reads with asyncio.gather(). Confirms the |
21 | | - HTTP GET path actually parallelizes. An internal lock or misplaced await |
22 | | - would collapse the speedup to ~1x. Covers: records.list, query.sql, |
23 | | - tables.get. |
24 | | -
|
25 | | -3. Write concurrency (POST path) |
26 | | - Same as Test 2 but for records.create() (POST). The POST path uses a |
27 | | - different timeout branch (120 s vs 10 s for GET) and different server |
28 | | - behavior. A separate test ensures writes are also truly concurrent, not |
29 | | - just reads. Creates N records in parallel then cleans them up. |
30 | | -
|
31 | | -4. Pagination non-blocking (async generator canary) |
32 | | - Runs list_pages(), fetchxml().execute_pages(), and builder().execute_pages() |
33 | | - while the canary ticks. Verifies the async generator yields control back to |
34 | | - the event loop between page fetches. A generator that does not await |
35 | | - properly between pages would block other tasks during multi-page queries. |
36 | | -
|
37 | | -5. Mixed fan-out (cross-operation concurrency) |
38 | | - Fires 6 different operation types simultaneously in one gather(): records.list, |
39 | | - tables.get (x2), query.sql, query.fetchxml, query.builder. A shared internal |
40 | | - resource (metadata cache lock, single connection) could accidentally serialize |
41 | | - different operation types even if same-type parallelism works fine. This test |
42 | | - catches cross-operation serialization. |
43 | | -
|
44 | | -6. Error resilience |
45 | | - Fires 5 calls — 3 good, 2 intentionally bad — using gather(return_exceptions=True). |
46 | | - Verifies the 3 good calls complete and return results despite the 2 failures. |
47 | | - Without return_exceptions=True, one exception cancels all in-flight coroutines. |
48 | | - Validates the correct usage pattern and confirms the SDK does not suppress |
49 | | - exceptions in a way that would break this pattern. |
50 | | -
|
51 | | -7. Real-world metadata fan-out |
52 | | - Fetches schema info for 6 tables sequentially then in parallel. The most |
53 | | - common real-world async use case: an application needs metadata for several |
54 | | - tables at startup. Demonstrates the pattern works end-to-end with real results. |
| 12 | +1. Non-blocking reads — canary ticks every 10 ms during GET calls; large gap |
| 13 | + means the event loop was blocked. |
| 14 | +2. Read throughput — N sequential vs N concurrent reads; confirms GET path |
| 15 | + parallelizes. |
| 16 | +3. Write concurrency — N sequential vs N concurrent creates; confirms POST |
| 17 | + path (different timeout branch) also parallelizes. |
| 18 | +4. Pagination non-blocking— canary ticks during list_pages/execute_pages; confirms |
| 19 | + async generators yield between page fetches. |
| 20 | +5. Mixed fan-out — 6 different operation types fired simultaneously; |
| 21 | + catches cross-operation serialization. |
| 22 | +6. Error resilience — 3 good + 2 bad calls in gather(return_exceptions=True); |
| 23 | + confirms failures don't cancel successful calls. |
| 24 | +7. Real-world fan-out — metadata for 6 tables fetched in parallel; end-to-end |
| 25 | + validation of the most common async use case. |
55 | 26 |
|
56 | 27 | How to interpret results |
57 | 28 | ------------------------ |
|
0 commit comments