fairagro-middleware-api-client 10.0.3.dev26__tar.gz → 11.0.1.dev27__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/.gitignore +0 -3
- {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/PKG-INFO +1 -1
- fairagro_middleware_api_client-10.0.3.dev26/spec/harvest-client/design.md +0 -72
- fairagro_middleware_api_client-10.0.3.dev26/spec/harvest-client/spec.md +0 -50
- {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/README.md +0 -0
- {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/example_client_config.yaml +0 -0
- {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/pyproject.toml +0 -0
- {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/src/middleware/api_client/__init__.py +0 -0
- {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/src/middleware/api_client/api_client.py +0 -0
- {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/src/middleware/api_client/config.py +0 -0
- {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/src/middleware/api_client/models.py +0 -0
- {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/src/middleware/api_client/py.typed +0 -0
- {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/tests/client_test_support.py +0 -0
- {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/tests/conftest.py +0 -0
- {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/tests/integration/conftest.py +0 -0
- {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/tests/integration/test_create_arcs.py +0 -0
- {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/tests/unit/conftest.py +0 -0
- {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/tests/unit/test_api_client_config.py +0 -0
- {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/tests/unit/test_client.py +0 -0
- {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/tests/unit/test_client_config.py +0 -0
- {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/tests/unit/test_harvest_arcs.py +0 -0
- {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/tests/unit/test_retry_logic.py +0 -0
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
# Harvest Client — Design
|
|
2
|
-
|
|
3
|
-
## Module Overview
|
|
4
|
-
|
|
5
|
-
`ApiClient` (`api_client.py`) orchestrates the harvest lifecycle.
|
|
6
|
-
`HarvestResult`, `HarvestStatistics`, `HarvestError`, and `HarvestErrorType`
|
|
7
|
-
(`models.py`) are the stable public types exposed to harvesters.
|
|
8
|
-
|
|
9
|
-
```text
|
|
10
|
-
harvester
|
|
11
|
-
└─→ ApiClient.harvest_arcs(rdi, arcs)
|
|
12
|
-
├─→ create_harvest → HarvestResult (RUNNING)
|
|
13
|
-
├─→ _submit_arcs_parallel
|
|
14
|
-
│ ├─→ duplicate check (client-side) → HarvestError(DUPLICATE)
|
|
15
|
-
│ └─→ POST v3/harvests/{id}/arcs → HarvestError(SUBMISSION_FAILED) on error
|
|
16
|
-
└─→ complete_harvest → HarvestResult (COMPLETED)
|
|
17
|
-
└─→ inject client_errors via model_copy → HarvestResult.errors
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
## Key Decisions
|
|
21
|
-
|
|
22
|
-
1. **`HarvestStatistics` is a typed Pydantic model, not `dict`**
|
|
23
|
-
— The server serializes its internal `HarvestStatistics` via `model_dump()`
|
|
24
|
-
before sending it over the wire. The field names and types are stable and
|
|
25
|
-
known. A typed model gives consumers validated, IDE-navigable fields rather
|
|
26
|
-
than requiring dict key lookups with no type safety.
|
|
27
|
-
|
|
28
|
-
2. **`HarvestError` is a client-facing type in `models.py`, independent of any server model**
|
|
29
|
-
— Per-item errors are currently generated client-side. When the server
|
|
30
|
-
persists them natively (issue #240), `_parse_harvest_response` will
|
|
31
|
-
populate `HarvestResult.errors` from the server response automatically —
|
|
32
|
-
the type and consumer interface remain unchanged.
|
|
33
|
-
|
|
34
|
-
3. **`arc_id: str | None` in `HarvestError`**
|
|
35
|
-
— The `DUPLICATE` and `SUBMISSION_FAILED` categories always have a
|
|
36
|
-
known ARC identifier (when one is extractable from the RO-Crate). Future
|
|
37
|
-
error categories — such as harvest-level timeouts or config failures —
|
|
38
|
-
may not be associated with any specific ARC. `None` is the semantically
|
|
39
|
-
correct representation; an empty string would be an invisible sentinel
|
|
40
|
-
value that callers would need to treat specially.
|
|
41
|
-
|
|
42
|
-
4. **Client-side error collection as compatibility shim until issue #240**
|
|
43
|
-
— `harvest_arcs()` collects errors from `_submit_arcs_parallel()` and
|
|
44
|
-
merges them into the server response via `model_copy(update=...)`.
|
|
45
|
-
This shim is removed once the server persists and returns per-item errors
|
|
46
|
-
natively. The `model_copy` merge is additive: if the server already
|
|
47
|
-
returns errors in its response (post-#240), client-side errors are
|
|
48
|
-
appended rather than overwriting.
|
|
49
|
-
|
|
50
|
-
5. **Duplicate detection is performed client-side before the HTTP request**
|
|
51
|
-
— Within one harvest batch, two different ARC payloads that share an
|
|
52
|
-
identifier are a harvester bug. Detecting them client-side yields an
|
|
53
|
-
explicit `DUPLICATE` error and avoids the round-trip. The server still
|
|
54
|
-
enforces harvest-local identity: identical re-submits (e.g. transport
|
|
55
|
-
retries) return `200`; conflicting content for the same identifier returns
|
|
56
|
-
`409` (see `harvest-arc-upload/`). Client-side detection therefore covers
|
|
57
|
-
*intra-batch* duplicates; server idempotency covers *retry* duplicates.
|
|
58
|
-
|
|
59
|
-
6. **Item-level failures are non-fatal; harvest-level failures are fatal**
|
|
60
|
-
— A submission failure for one ARC (e.g. server 422 on bad content) must
|
|
61
|
-
not abort the entire harvest because the remaining ARCs may be valid. A
|
|
62
|
-
catastrophic failure (e.g. 401 Unauthorized, harvest already closed) means
|
|
63
|
-
no further submissions will succeed, so the harvest is aborted, marked
|
|
64
|
-
`FAILED`, and the exception propagates to the caller.
|
|
65
|
-
|
|
66
|
-
7. **POST ARC endpoints retry transport failures**
|
|
67
|
-
— `POST /v3/arcs` and `POST /v3/harvests/{id}/arcs` are server-idempotent for
|
|
68
|
-
identical bodies, so the client retries `ConnectError` and transient gateway
|
|
69
|
-
statuses (`502`/`503`/`504`) on those paths without risking a second object.
|
|
70
|
-
Other POSTs (create/complete harvest) are not retried. Conflicting `409`
|
|
71
|
-
(same identifier, different content in one harvest) remains a real conflict
|
|
72
|
-
and is not treated as success.
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
# Harvest Client
|
|
2
|
-
|
|
3
|
-
Manage the full lifecycle of a harvest run — creation, parallel ARC
|
|
4
|
-
submission, error collection, and finalization — on behalf of a harvester
|
|
5
|
-
process. The client returns a typed result that captures both statistics
|
|
6
|
-
and per-item errors so harvesters can produce complete reports.
|
|
7
|
-
|
|
8
|
-
## Requirements
|
|
9
|
-
|
|
10
|
-
- [ ] Create a harvest run for a given RDI, submit all ARCs from an async
|
|
11
|
-
source in bounded parallelism, and return the completed harvest result
|
|
12
|
-
as a single operation.
|
|
13
|
-
- [ ] Accept an optional expected-dataset count at the start of a harvest to
|
|
14
|
-
enable progress tracking on the server side.
|
|
15
|
-
- [ ] Return typed harvest statistics (submitted, new, updated, unchanged,
|
|
16
|
-
missing counts, and optional expected-dataset count) as structured
|
|
17
|
-
fields rather than an opaque mapping.
|
|
18
|
-
- [ ] Record per-item errors encountered during submission and include them
|
|
19
|
-
in the returned harvest result.
|
|
20
|
-
- [ ] Classify each per-item error into one of the following categories:
|
|
21
|
-
`duplicate` (two ARCs share the same identifier) or `submission_failed`
|
|
22
|
-
(the server rejected or could not process the ARC).
|
|
23
|
-
- [ ] Each per-item error carries: the error category, a human-readable
|
|
24
|
-
message, and an ISO 8601 timestamp of when the error occurred.
|
|
25
|
-
- [ ] Optionally associate a per-item error with an ARC identifier; errors
|
|
26
|
-
that do not relate to a specific ARC (e.g. harvest-level failures) may
|
|
27
|
-
omit the identifier.
|
|
28
|
-
- [ ] Detect duplicate ARC identifiers before submission and record them as
|
|
29
|
-
`duplicate` errors; do not submit the duplicate.
|
|
30
|
-
- [ ] Skip individual ARC submission failures and continue the harvest with
|
|
31
|
-
remaining items; record each failure as a `submission_failed` error.
|
|
32
|
-
- [ ] Abort the entire harvest on catastrophic errors (e.g. authentication
|
|
33
|
-
failure, invalid harvest state) and mark the harvest as failed before
|
|
34
|
-
propagating the exception to the caller.
|
|
35
|
-
|
|
36
|
-
## Edge Cases
|
|
37
|
-
|
|
38
|
-
ARC with no extractable RO-Crate identifier → submitted normally; any
|
|
39
|
-
resulting error records no ARC identifier (`null`).
|
|
40
|
-
|
|
41
|
-
Two ARCs share the same identifier → the second is skipped; a `duplicate`
|
|
42
|
-
error is recorded for it; the first continues to be submitted normally.
|
|
43
|
-
|
|
44
|
-
Catastrophic error during submission → remaining tasks are cancelled; the
|
|
45
|
-
harvest is transitioned to `FAILED`; the exception propagates to the caller.
|
|
46
|
-
|
|
47
|
-
No per-item errors → the returned result contains an empty errors list.
|
|
48
|
-
|
|
49
|
-
`expected_datasets` not provided → harvest is created without a progress
|
|
50
|
-
denominator; statistics show raw counts only.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|