Releases: firefly-operationOS/flyquery
Releases · firefly-operationOS/flyquery
v26.6.0
v26.5.14
flyquery 26.5.14 — Apache 2.0 open-source release
flyquery is now open source under the Apache License 2.0 (© 2024-2026 Firefly Software Foundation); the repository is public.
Changed
- Replaced the proprietary notice with the full Apache 2.0
LICENSE(root + Python/Java SDKs) and added an Apache 2.0 header to every source file. - Set the OpenAPI
info.license, the imagelicenseslabel, the README badge, the bundled SDK spec/setup.py, andpyprojectmetadata to Apache-2.0. - Aligned all version references to
26.5.14; refreshed the lock-step SHA pins.
SDKs
- Python: wheel + sdist attached below.
- Java:
com.firefly:flyquery-sdk:26.5.14on GitHub Packages.
v26.5.13
Full Changelog: v26.5.12...v26.5.13
v26.5.12
Full Changelog: v26.5.11...v26.5.12
v26.5.11
Added — Webhook callbacks for every async ingest job
A receiver-side push channel for the async ingest pipeline. The
caller attaches callback_url (+ optional secret + custom
headers) to POST /api/v1/ingest-jobs or to
POST /api/v1/datasets/{ds}/files:async; on terminal status
(SUCCEEDED / FAILED / CANCELLED) the worker POSTs the
canonical IngestJobRead payload to the configured URL.
- Transactional outbox -- a new
flyquery_callback_outboxtable
(migration0013_job_callbacks) is written in the SAME transaction
as the job's status flip. A process crash between the two writes is
impossible, so a "succeeded" job ALWAYS has its callback queued. CallbackWorkerdrains the outbox withFOR UPDATE SKIP LOCKED
so N peer workers scale horizontally without colliding. Five-attempt
exponential backoff (0s, 30s, 5m, 1h, 6h), thenDEAD. New CLI
subcommandflyquery worker callbackandflyquery worker allnow
includes it alongside ingest + retention.- HMAC-SHA256 signing -- when a
secretis provided, every
request carriesX-Flyquery-Signature: sha256=<hmac>computed over
the raw body. Dispatcher applies reserved headers (Content-Type,
X-Flyquery-Event,X-Flyquery-Job-Id,X-Flyquery-Signature)
LAST so a misconfigured or malicious extra-header bag cannot shadow
the signature header. - Per-request OR per-configuration -- the per-request bundle takes
precedence, butFLYQUERY_DEFAULT_CALLBACK_URL/
FLYQUERY_DEFAULT_CALLBACK_SECRET/
FLYQUERY_DEFAULT_CALLBACK_HEADERSprovide a process-wide default
receiver so an operator can wire every async job to a central hub
without touching every caller. Whole-bundle precedence (URL +
secret + headers move together) prevents accidentally leaking the
default secret to a different receiver. GET /api/v1/ingest-jobs/{id}/callbacks-- paginated audit
trail. One row per delivery attempt with URL, event type
(ingest.succeeded/ingest.failed), status (PENDING/
DELIVERED/FAILED/DEAD), attempt count, last HTTP status
code + last error, and next scheduled retry. Supports?status=
filter.- SDK helpers:
- Python:
client.upload_async(..., callback_url=, callback_secret=, callback_headers=)+client.list_job_callbacks(job_id, ...)
(and_syncmirrors). The auto-generatedIngestJobsApi.list_callbacksCallbackConfig/CallbackDeliveryRead/
CallbackDeliveryListResponsemodels are also exposed.
- Java:
client.ingestJobs().listCallbacks(...)from the
regeneratedIngestJobsApi.CallbackConfigmodel can be set
onIngestJobCreate.callbackforcreateJob(...).
- Python:
- New docs:
docs/callbacks.md-- full
contract, receiver example with signature verification, retry
schedule, ops runbook for DEAD rows. Cross-linked from
docs/async-ingest.md+docs/workers.md.
Fixed — Critical correctness bugs surfaced by end-to-end testing
- Publisher DI was silently in-memory --
core/configuration.py
had a stale@bean ingest_publisherfactory that called
_resolve_eda_publisher()at factory-eval time (before
EdaAutoConfigurationwired the EventPublisher). The factory won
precedence over the@serviceregistration onIngestPublisher,
so every running process heldself._publisher = Noneand every
publish_ingest_requestedsilently hit the in-memory branch.
Workers never receivedIngestRequestedevents; async jobs sat in
PENDINGforever and were only rescued by the orphan-PENDING
reaper 10 minutes later. Factory deleted; the@service
registration now resolvesEventPublishervia constructor
injection like flycanon / flyradar. - Pyfly DI param-name mismatches -- pyfly's resolver is name-first
with type-fallback.IngestService(publisher: IngestPublisher, ...)
did not match the snake-cased bean nameingest_publisher. Renamed
toingest_publisheronIngestService+IngestJobService. Also
renamedrepository/repo-> snake-cased bean name on
SchemaObjectService,SchemaChangeService,RelationService,
SemanticService,SemanticDimensionsService,WorkspaceService
for forward-safety. triggered_by="WORKER"violatedck_snapshots_trigger-- the
CHECK constraint accepts onlyUSER/AGENT/SCHEDULED/
REPARSE. Every async PARSE_AND_INGEST job failed at reconcile
withCheckViolationError. Worker now writesREPARSEfor the
by-worker path (workers.py:488).governance_json/synonyms_jsonDTO polymorphism -- legacy
rows from a priorNULL || dictjsonb-concat bug stored
governance_jsonas[null, {...}]. The DTO had been widened to
dict | list | Noneas a band-aid; that ambiguity leaked into
every consumer and brokeGET /tables/{id}/objectswith a Pydantic
422. Fixed properly:- DTOs tightened to
synonyms_json: list[str]/
governance_json: dict[str, Any]. - New normaliser
core/services/storage/jsonb_normalize.pycoerces
any historical shape to canonical at every consumer + producer
seam (DTOfield_validator+reconcilestage write path). - Migration
0012_normalize_jsonb_shapesheals existing polluted
rows.
- DTOs tightened to
flyquery_examplesinsert syntax --:embedding::vector
confused SQLAlchemy's bind parser (text parsed the second:as a
new bind), so asyncpg received a literal:embeddingtoken and
raisedPostgresSyntaxError. Every successful NL query crashed
with a 500 after the SQL executed (auto-learning save path).
Changed toCAST(:embedding AS vector).- CallbackWorker triggered pyfly's ApplicationRunner convention
-- a bean method namedrun()is auto-invoked at API startup with
a positionalargsparameter. Renamed torun_forever()so the
callback drain runs ONLY under the dedicated CLI command. - Callback dispatcher header ordering -- caller-supplied extra
headers were applied AFTER our reserved keys, allowing
extra_headers={"X-Flyquery-Signature": "evil"}to shadow the real
signature. Reversed: reserved keys are applied LAST.
Changed
POST /api/v1/ingest-jobsnow declares its request body via
Valid[Body[IngestJobCreate]](was: manualrequest.json()decode).
This publishesIngestJobCreate+ the nestedCallbackConfig
schemas intoopenapi.jsonso SDK generators see them. Wire
contract unchanged; existing 200/422 behaviour identical.pyfly.yaml,pyproject.toml,Taskfile.yml, both SDK
pyproject.toml/setup.py/pom.xml/build.gradle, README
badge, andapp.pydecorator all now read26.5.11. (Also fixed
theapp.pydrift from26.5.0.)
Full Changelog: v26.5.10...v26.5.11
v26.5.10
Full Changelog: v26.5.6...v26.5.10