Spans model per-action operations (open/message/close); they're a poor fit for ad-hoc
events with no operation lifecycle. Split logError to dispatch by whether a span is
active:
- Active span (realtime.open / realtime.message / realtime.close catches) -> attach
the error to the existing span; the Sentry span exporter ships it with full operation
context (attributes, duration, trace_id).
- No active span (pub/sub subscriber, onStart, Swoole error handler, updateWorkerDocument)
-> push a utopia/logger Log via the realtimeLogger registry. Goes to Sentry as an event
via the Sentry logger adapter (or to logOwl / Raygun / AppSignal). Same dedicated
Realtime project either way.
Restores the realtimeLogger registry (dropped in the previous "spans only" pass), inlines
the now-single-caller $createLogger closure into the logger registry, and drops the
recordRealtimeErrorSpan helper — logError is the only function on this path now.
Also registers a Pretty span exporter in app/init/realtime/span.php for non-self-hosted
editions so Realtime spans are visible in the container's stdout (on self-hosted the
existing app/init/span.php already provides it; gating avoids duplicate output).
Collapse the multi-line doc blocks on recordRealtimeErrorSpan / pushRealtimeErrorLog /
$createLogger to one line each, drop the redundant require comment, and tighten the
"keep in sync" notes — keeping the cross-references and the double-report hazard.
Return early from the realtimeLogger registry when neither
_APP_LOGGING_CONFIG_REALTIME nor _APP_LOGGING_CONFIG is set, so the no-config
case (typical self-hosted) no longer constructs and throws from new DSN(''),
and tidy the $createLogger doc comment.
The realtimeLogger registry was a ~40-line copy of logger; extract the
DSN -> adapter -> Logger construction into one $createLogger closure used by
both. realtimeLogger now just resolves _APP_LOGGING_CONFIG_REALTIME (falling
back to _APP_LOGGING_CONFIG), skips Sentry — those errors go out as spans via
app/init/realtime/span.php — and delegates the rest. Cross-referenced the two
"sentry" conditions in both files. No behavior change (legacy ;-delimited
config no longer crashes the realtime registry; it disables logging like the
main one).
Move the Realtime Sentry span exporter registration out of app/realtime.php
into app/init/realtime/span.php (mirrors app/init/span.php / app/init/realtime/
connection.php), and split the now-80-line logError() into recordRealtimeErrorSpan()
(span path) and pushRealtimeErrorLog() (legacy utopia/logger path, non-Sentry
providers only), leaving logError() a small orchestrator. No behavior change.
Realtime errors are now recorded onto a span and shipped to a Sentry
project configured via _APP_LOGGING_CONFIG_REALTIME (falls back to
_APP_LOGGING_CONFIG). The Sentry span exporter is registered in
app/realtime.php so it does not affect the HTTP/worker/CLI span
exporters. logError() attaches the error to the active span, or opens a
short-lived realtime.error span for call sites without one (pub/sub
subscriber, onStart, the Swoole error handler), and keeps the legacy
utopia/logger push only for non-Sentry providers; the realtimeLogger
registry now returns null when the provider is Sentry to avoid
double-reporting. Documents _APP_LOGGING_CONFIG_REALTIME.
The migrations worker (Appwrite→Appwrite migrations + CSV/JSON imports
& exports) reads `_APP_MIGRATION_HOST` to call back into this instance's
API. `_APP_MIGRATION_HOST` was introduced in #11229 (1.8.x / 1.9.x) but
was never added to `app/config/variables.php`, so `appwrite install` /
`appwrite upgrade` never write it into the generated `.env`. With the
var unset, the migrations worker fails — on a fresh self-hosted install
the first export hangs with no error (#11853). (Contributors and CI
don't hit it because the repo's hand-maintained `.env` already has
`_APP_MIGRATION_HOST=appwrite`; only the *installer-generated* `.env` is
missing it.)
Add `_APP_MIGRATION_HOST` to `app/config/variables.php` with default
`appwrite` — the API service name in the standard Docker Compose setup,
which is what the repo's own `.env` and the cloud Helm charts already
use, and what the migration endpoint was hardcoded to before #11229.
`appwrite install` and `appwrite upgrade` now write it into the
generated `.env`, so fresh installs and upgrades have it set and the
migration/import/export flows work.
Scope: this PR fixes the install & upgrade paths only — it deliberately
doesn't change the worker code.
Fixes#11853
Replaces the stateful Appwrite\Event\Build queue class with a stateless
BuildPublisher and BuildMessage DTO, matching the publisher pattern used
by audits, certificates, executions, migrations, screenshots, stats, and
usage. Call sites now enqueue messages directly instead of mutating a
shared event object and relying on the API shutdown hook.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds Executor\Exception\Timeout (with timeoutSeconds) and translates it at
each call site into BUILD_TIMEOUT, FUNCTION_SYNCHRONOUS_TIMEOUT, or
FUNCTION_ASYNCHRONOUS_TIMEOUT instead of always using the misleading sync
function error. Build timeouts now append to streamed buildLogs rather
than replacing them, and the build worker reports its timeout via Span.
greptile flagged missing lengths but the codebase has two conventions:
- all-string composite: [LENGTH_KEY, LENGTH_KEY] (_key_unique, _key_provider_providerUid)
- mixed/non-string composite: [] (e.g. ('enabled', 'type'), ('region', 'accessedAt'),
('targetInternalId', 'topicInternalId'), ('period', 'time'), ('metric', 'period', 'time'))
(teamInternalId, confirm) is string+boolean; closest match is
('enabled', 'type') which uses lengths => [] and orders => [].
Aligning to that established pattern instead of inventing
[LENGTH_KEY, 0].