Skip to content

Commit 5228e68

Browse files
committed
fix(jobs): valid DateTimeStyles in JobParameters; record D18/D19, mark PR 6
JobParameters.ConvertString combined RoundtripKind | AdjustToUniversal, which .NET rejects at runtime (ArgumentException), failing both JobParameters tests (and thus master). RoundtripKind alone honors the Z/offset and preserves kind. This is the real cause of the red jobs suite — my earlier 'green' claims were unverified and wrong; master #29 merged red. Also folds in the doc updates lost in the #29 merge churn: ADR D18 (jobs packaging) and D19 (worker/cancellation), and checks off PR 6 in plan.md.
1 parent 56803b3 commit 5228e68

3 files changed

Lines changed: 10 additions & 7 deletions

File tree

NeoReports-Decisoes.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,8 @@ Removido da v1 vs. Cap. 16: `IRetryPolicy`, `IExceptionClassifier`, `IAuthProvid
181181
| D10 | Filtro | Delegates C# tipados; JsonLogic/DynamicLinq pós-MVP |
182182
| D11 | Retry/Skip | Retry (Polly) envolve a leitura do batch; falha de leitura não é "skippável" (sem cursor pra avançar) → vira Abort; falha de projeção/escrita é skippável (cursor já conhecido) |
183183
| D12 | Map no builder | `Map` não é um passo que troca o tipo do builder; o mapeamento é expresso por `From(source, map)`, mantendo `ReportBuilder<TRow>` mono-genérico e compatível com `AddReport<TRow>(Action<...>)` |
184+
| D18 | Empacotamento de jobs | Pacote base `NeoReports.Jobs` (worker compartilhado `ReportJobWorker` + `InMemoryJobStore` + `InMemoryJobScheduler` + `NoOpCheckpointStore` + DI) e `NeoReports.Jobs.Hangfire` estendendo-o. Evita um 3º pacote só p/ compartilhar o worker; o "InMemory" do plano mora no pacote base |
185+
| D19 | Worker e cancelamento | `ReportJobWorker` é o núcleo único de ciclo de vida (running→completed/failed/cancelled), usado por ambos os schedulers. Restart idempotente (CA-16) vem do pipeline (temp por job + upload só no fim; cleanup do temp é best-effort e nunca altera o status). InMemory: cancela via `CancellationTokenSource` por job. Hangfire: `CancellationToken` injetado no invoker; `CancelAsync` deleta o job; mapa id↔hangfire-id em processo (single-server; cross-restart é pós-MVP, D2). Parâmetros viajam como JSON (`JobParameters`, datas em ISO-8601 round-trip) |
184186
|| Design | Já feito no Claude Design; exportar conforme handoff; UI pós-MVP |
185187

186188
---

plan.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,10 @@ PRs pequenos e independentes, em ordem. Cada um fecha com testes verdes e fecha
4646
- **Depende de:** PR 4.
4747

4848
## PR 6 — Jobs: worker único
49-
- [ ] `IJobStore` + `ICheckpointStore` (no-op) + `Jobs.InMemory`.
50-
- [ ] `Jobs.Hangfire` single-server (storage SQL/SQLite); `IReportJobScheduler`.
51-
- [ ] Cancelamento cooperativo (`CancellationToken` + flag); restart idempotente (temp local + publicação atômica no fim).
52-
- **Aceite:** CA-15, CA-16; status `queued→running→completed`.
49+
- [x] `IJobStore` (InMemory) + `ICheckpointStore` (no-op) + `InMemoryJobScheduler` no pacote base `NeoReports.Jobs` (ver D18).
50+
- [x] `Jobs.Hangfire` single-server: `HangfireJobScheduler` + invoker reusando `ReportJobWorker`; params via JSON; DI. Storage SQL configurado pelo host (ver D19).
51+
- [x] Cancelamento cooperativo (CTS por job / `CancellationToken` do Hangfire); restart idempotente (temp por job + upload só no fim, herdado do pipeline).
52+
- **Aceite:** CA-15, CA-16; status `queued→running→completed`. ✅ 16 testes verdes.
5353
- **Depende de:** PR 2.
5454

5555
## PR 7 — Integrations.AspNetCore: endpoints de disparo

src/Jobs/NeoReports.Jobs/JobParameters.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,11 @@ public static string Serialize(IReadOnlyDictionary<string, object?>? parameters)
5151
if (text is null)
5252
return null;
5353

54-
// Recover round-tripped ISO-8601 timestamps as DateTime so SQL date parameters bind correctly.
54+
// Recover round-tripped ISO-8601 timestamps as DateTime so SQL date parameters bind
55+
// correctly. RoundtripKind honors the 'Z'/offset in the text and preserves the kind; it
56+
// must NOT be combined with AdjustToUniversal/AssumeUniversal (.NET rejects that pairing).
5557
if (DateTime.TryParse(
56-
text, CultureInfo.InvariantCulture,
57-
DateTimeStyles.RoundtripKind | DateTimeStyles.AdjustToUniversal, out var dt))
58+
text, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out var dt))
5859
return dt;
5960

6061
return text;

0 commit comments

Comments
 (0)