From 8e5a6a80a775fb067125462455153641d5f4bf72 Mon Sep 17 00:00:00 2001 From: Anas El Mhamdi Date: Thu, 6 Aug 2026 10:20:10 +0200 Subject: [PATCH] chore(release): prepare v0.5.0 Move the stream-reset entry from [Unreleased] into 0.5.0 and bump the version. Minor rather than patch: it adds a feature, and `AbstractBackend` gains five abstract methods, which an out-of-tree backend subclass would have to implement. Split the changelog entry into several bullets. publish.yml lifts this section verbatim into the GitHub Release body, and it was one ~1900 character paragraph. Co-Authored-By: Claude --- CHANGELOG.md | 26 +++++++++++++++++++++++++- pyproject.toml | 2 +- uv.lock | 2 +- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 95231e9..b94b832 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,8 +7,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.5.0] - 2026-08-06 + ### Added -- **Stream reset for incremental syncs**: re-fetch an incremental stream in full and *replace* the destination table for one run, then resume incremental from it. Previously the only way to rebuild a drifted table was to delete backend rows by hand — the watermark (`last_run`, taken from the last succeeded job) had no escape hatch. Request one with `bizon run config.yml --reset`, with `source.reset: true` in the config, or with `bizon stream reset ` (`--cancel` to withdraw, `--stream` to target a stream other than the config's for templated configs). Requests are scoped to a single stream — keyed on `(name, source_name, stream_name)`, the same triple as the watermark they override — so resetting one stream never affects another under the same pipeline name. The last form records the request in the backend and the next run consumes it, so pipelines whose command line is fixed by a scheduler need no change. During a reset the producer skips the watermark and calls `get()` instead of `get_records_after()`, and the run reaches destinations as `sync_mode: full_refresh` so they replace their table through their existing full-refresh path (for `bigquery`: staging into `{table}_temp`, then a `WRITE_TRUNCATE` copy job). The job row stays `incremental`, so the reset run becomes the next run's watermark. The request stays bound to the job running it, so a crashed reset is retried as a reset rather than silently degrading into an append. Only meaningful for `sync_mode: incremental` (ignored with a warning otherwise) and supported by every destination with a working full-refresh path — the exception is `bigquery_streaming`, which has no staging table and appends even on a full refresh, so a reset there is rejected at validation instead of duplicating data. Adds a `stream_resets` table, created automatically alongside the existing ones (no migration needed). + +- **Stream reset for incremental syncs** — one run that re-fetches an incremental stream in full and *replaces* the destination table, after which incremental resumes from that run. Previously the only way to rebuild a drifted table was to delete backend rows by hand: the watermark (`last_run`, taken from the last succeeded job) had no escape hatch. + + Three ways to ask for one, all equivalent: + + ```bash + bizon run config.yml --reset # one-shot, manual + bizon stream reset config.yml # queued, consumed by the next run + bizon stream reset config.yml --cancel # withdraw it + bizon stream reset config.yml --stream deals # pick the stream, for templated configs + ``` + + ...or `source.reset: true` in the config. `bizon stream reset` records the request in the backend rather than running anything, so a pipeline whose command line is fixed by a scheduler picks it up with no change to its cron/Airflow job. + +- Requests are **scoped to a single stream**, keyed on `(name, source_name, stream_name)` — the same triple as the watermark they override — so resetting one stream never affects another under the same pipeline name. + +- During a reset the producer skips the watermark and calls `get()` instead of `get_records_after()`, and the run reaches destinations as `sync_mode: full_refresh` so they replace their table through their existing full-refresh path (for `bigquery`: staging into `{table}_temp`, then a `WRITE_TRUNCATE` copy job). The job row stays `incremental`, so the reset run becomes the next run's watermark. The request stays bound to the job running it, so a crashed reset is retried as a reset rather than silently degrading into an append. + +- Only meaningful for `sync_mode: incremental` (ignored with a warning otherwise), and supported by every destination with a working full-refresh path. The exception is `bigquery_streaming`, which has no staging table and appends even on a full refresh, so a reset there is rejected at config validation instead of duplicating data. + +### Changed + +- `AbstractBackend` gains five `stream_resets` methods. Backends bundled with bizon implement them; an out-of-tree `AbstractBackend` subclass will need them added. Adds a `stream_resets` table, created automatically alongside the existing ones — no migration needed. ## [0.4.1] - 2026-06-29 diff --git a/pyproject.toml b/pyproject.toml index e1a73bc..4adf835 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "bizon" -version = "0.4.1" +version = "0.5.0" description = "Extract and load your data reliably from API Clients with native fault-tolerant and checkpointing mechanism." authors = [ { name = "Antoine Balliet", email = "antoine.balliet@gmail.com" }, diff --git a/uv.lock b/uv.lock index 0895ee7..05fa00f 100644 --- a/uv.lock +++ b/uv.lock @@ -55,7 +55,7 @@ wheels = [ [[package]] name = "bizon" -version = "0.4.1" +version = "0.5.0" source = { editable = "." } dependencies = [ { name = "backoff" },