Commit Graph

34287 Commits

Author SHA1 Message Date
Prem Palanisamy e0ec28f02a revert: drop $log clone and sdks in-lock re-read
Both were defensive against rare edge cases the reviewer flagged but
which don't justify the complexity:

- $log clone: protects against tag pollution on the per-request Log
  if reportError fires AND the request later errors. http.php's
  request-end handler overwrites the core fields (namespace, message,
  action, etc.) anyway; only addTag/addExtra accumulate. Aligns with
  Embeddings/Text/Create.php precedent which mutates $log directly.

- sdks in-lock re-read: closes a sequential-acquire stale-read race on
  the sdks append-list. The race exists but the impact is bounded —
  one SDK registration delayed until the next request from that SDK
  fires. Self-healing on retry. The codebase already accepts this
  exact race for auths, oAuthProviders, services, identities, sessions,
  factors, etc. Special-casing this one site is precision the analytics
  use case doesn't need.
2026-04-30 08:24:56 +01:00
Prem Palanisamy 18f3280bad refactor(lock): extract magic numbers and outcome strings, fix target parse
- TTL defaults (5s skip / 10s fail), 3s wait timeout, and 60s sentry
  rate-limit window are now class constants.
- Telemetry outcome labels (acquired/skipped/contended/backend_error/
  release_error) are class constants — typo-safe across the 9 use sites.
- Fix: inferTargetFromKey was indexing into segment 2 with limit 4,
  which returned the project sequence instead of the collection name
  ever since project-id was added to the key in c2a249c48b. Telemetry
  was tagging 'target' with project sequences instead of 'projects' /
  'users' / etc. Now indexes segment 3 with limit 5 to correctly pick
  the collection segment from lock:platform:{project}:{target}:...
2026-04-30 07:48:04 +01:00
Prem Palanisamy bae328efa1 revert: keep narrow RedisException catch on lock acquire
Reverts the catch widening from earlier — the underlying
Utopia\Lock\Distributed::tryAcquire only calls ext-redis methods,
which throw RedisException exclusively. Catching Throwable was
over-broad and would silently swallow real bugs (TypeError, Error)
into a fail-open path.
2026-04-30 07:42:59 +01:00
Prem Palanisamy 03575e68c4 fix(lock): re-read keys inside lock body to avoid sdks append loss
The sdks attribute is an append-only list, not idempotent. With the
read happening outside the lock, two sequential acquirers could each
read the same stale list and overwrite each other's appends.

Now the lock body re-reads the keys document and re-derives the sdks
array from the fresh state. Skip-on-contention still drops the update
when the lock is held, but a same-SDK retry on the next request picks
the registration up.

Bounded loss only affects the rare 'first-seen' SDK request that
happens to land while the lock is held; sequential traffic from the
same SDK (or any later request from any SDK) re-attempts and writes.

Co-authored-by: greptile-apps[bot]
2026-04-30 07:31:15 +01:00
Prem Palanisamy 2762e84974 fix(lock): broaden acquire catch + clone Log before reportError
Two P1s from review:

- Acquire path caught only \RedisException; any other Throwable from the
  lock library would escape and skip the fail-open callback. Widened to
  \Throwable so any backend failure falls back to running unlocked.
- reportError mutated the per-request $log directly, leaving it in a
  'lock.{action}' state that the request-end handler would then submit
  as the request log. Clones $log into a dedicated $lockLog so the
  shared instance is untouched.
2026-04-30 07:26:45 +01:00
Prem Palanisamy 7b2f6ac692 fix: add explicit parens to new ClassName calls in LockTest (PSR-12) 2026-04-30 07:13:51 +01:00
Prem Palanisamy 542aac7fda Merge remote-tracking branch 'origin/1.9.x' into distributed-lock
# Conflicts:
#	composer.lock
2026-04-30 06:53:31 +01:00
Prem Palanisamy 7430de293e test: unit tests for Lock facade
Covers the four public methods (set, run, runOrFail, withKey) plus the
kill switch and the project-fallback behavior.

Tests against a real Redis (the appwrite container has it always-on);
no markTestSkipped fallback — the suite fails loudly if Redis is
unreachable rather than silently passing.
2026-04-30 06:05:50 +01:00
Chirag Aggarwal 8ffe48d948 Merge pull request #12179 from appwrite/fix/project-delete-platform-cleanup 2026-04-30 09:43:37 +05:30
Chirag Aggarwal 4050b9ded1 Continue project cleanup after resource failures 2026-04-30 09:28:22 +05:30
Prem Palanisamy 2f2a124a06 revert: redis resource cluster support + _APP_CONNECTIONS_CACHE fallback
Cloud production runs four separate single-master+replica Dragonfly
deployments (cache, queue-dragonfly, queue-usage, pubsub-dragonfly),
not sharded Redis Cluster topology — confirmed by deploy/cloud/values
+ environments/production/*.values.yaml (Dragonfly Operator with
replicas=2 = 1 primary + 1 read replica), and by the dev DSN scheme
'redis://' (not 'redis-cluster://').

So a standard \Redis client suffices for the direct redis resource
(timelimit, Lock). Cloud just needs to pass _APP_REDIS_HOST/PORT/USER/
PASS through to the appwrite container — handled in the cloud PR's
docker-compose.yml change.

This reverts the resource to its original pre-PR shape. The
utopia-php/lock cluster-support PR (utopia-php/lock#1) stays open at
upstream as a future-ready option if cloud ever moves to actual
Redis Cluster mode.
2026-04-29 16:39:36 +01:00
Torsten Dittmann 6088fd55c8 Merge pull request #12138 from appwrite/feat-out-of-order-chunk-uploads 2026-04-29 18:04:57 +04:00
Matej Bačo 1aeee8c407 Merge pull request #12178 from appwrite/fix-developer-experience
Fix: Developer experiene with recent chagnes
2026-04-29 15:56:06 +02:00
Matej Bačo 36486ccc93 Fix tests 2026-04-29 14:41:19 +02:00
Chirag Aggarwal 794d8eac5b Fix project delete platform cleanup ordering 2026-04-29 17:55:06 +05:30
Matej Bačo 32ebfc6cb8 Fix backwards compatibility 2026-04-29 14:14:49 +02:00
Matej Bačo e1b8f5bf98 review improvements 2026-04-29 14:04:54 +02:00
Matej Bačo 4d86e67006 Fix missing scopes for tables 2026-04-29 14:03:44 +02:00
Matej Bačo b3e3b2a330 Fix missing index scopes 2026-04-29 14:00:14 +02:00
Matej Bačo e010bf25d5 Fix formatting 2026-04-29 13:57:16 +02:00
Matej Bačo aaf91f3816 Improve scopes quality 2026-04-29 13:52:13 +02:00
Matej Bačo bae61e8a05 Improve developer experience of keys endpoints 2026-04-29 13:13:13 +02:00
Torsten Dittmann dfbf45f4cc Merge branch '1.9.x' into feat-out-of-order-chunk-uploads 2026-04-29 15:03:33 +04:00
Chirag Aggarwal c264db6146 Merge pull request #12177 from appwrite/codex/fix-1-9-trivy-sarif-categories cl-1.9.0-1 2026-04-29 16:13:30 +05:30
Chirag Aggarwal cccafeff0c Add nightly SARIF upload guards 2026-04-29 16:02:41 +05:30
Chirag Aggarwal 360d08f087 Preserve CI image for job retries 2026-04-29 16:01:15 +05:30
Chirag Aggarwal d8e97ae47d Merge pull request #12174 from appwrite/bump-docker-base-1.2.0 2026-04-29 15:59:24 +05:30
Chirag Aggarwal d13e6d75f0 Fix Trivy SARIF categories on nightly scan 2026-04-29 15:58:59 +05:30
Prem Palanisamy c2a249c48b feat(lock): include project internal id in lock key + telemetry
Per-manager request, lock keys are now prefixed with the project's
internal id (sequence) so that:
  - Locks are partitioned by project — Redis cluster slot affinity
    if/when sharded.
  - Cross-project requests can't compete on the same key for
    collection-scoped resources.
  - Telemetry (counter + Sentry tags) carries 'project' alongside
    'target', so dashboards can filter contention by project.

Key shapes:
  set:        lock:platform:{project}:{collection}:{id}:{attribute}
  run/orFail: lock:platform:{project}:{collection}:{id}
  withKey:    raw (caller-provided)

Lock now requires a project document at construction. All existing
call sites (4 in CE + 2 in cloud) run inside Http::init()-resolved
request scope where the project document is set, so no migration
needed. Workers/CLI without project context can use withKey directly.
2026-04-29 11:26:18 +01:00
Chirag Aggarwal 4447396859 Update base image to 1.2.1 2026-04-29 15:37:59 +05:30
Chirag Aggarwal 4d1f229ec7 Merge branch '1.9.x' into bump-docker-base-1.2.0 2026-04-29 15:32:32 +05:30
Chirag Aggarwal 4f733f5984 Merge pull request #12176 from appwrite/ci-ghcr-image-share 2026-04-29 15:32:22 +05:30
Chirag Aggarwal 701f557755 ci: clean up GHCR CI image after pipeline finishes
Every CI run pushes ghcr.io/<repo>/appwrite-dev:<sha> and nothing
removes it. On an active repo with many PRs the GHCR storage grows
without bound. Add a cleanup job that runs after all consumer jobs
complete (always, even if some fail) and deletes the SHA-tagged
package version via the Packages API.

Addresses Greptile feedback on appwrite/appwrite#12176.
2026-04-29 15:23:05 +05:30
Jake Barnby 8ab26aab44 Merge pull request #12171 from appwrite/migration-refractor
Refactor migrations API to module style
2026-04-29 21:44:19 +12:00
Chirag Aggarwal ec3aa2b54f ci: share docker image via GHCR instead of upload-artifact
The build job uploads the appwrite-dev image as an actions artifact
(~hundreds of MB), and 30+ E2E test jobs all pull it concurrently with
actions/download-artifact. GitHub Actions' artifact storage struggles
with that many parallel downloads and intermittently fails with
BlobNotFound or 'Artifact download failed after 5 retries'.

Push the built image to ghcr.io/<repo>/appwrite-dev:<sha> in the build
job and pull from GHCR in each test job. GHCR handles parallel image
fetches without throttling.

Mirrors appwrite-labs/cloud#3906.
2026-04-29 15:09:39 +05:30
Chirag Aggarwal 2d636ff7ec Merge branch '1.9.x' into bump-docker-base-1.2.0 2026-04-29 15:06:03 +05:30
Matej Bačo fd42b8fa64 Merge pull request #12175 from appwrite/feat-console-key-scopes-endpoint
Feat: Console key scopes endpoint
2026-04-29 11:17:49 +02:00
Chirag Aggarwal 9d7df34590 fix: clean up php 8.5 runtime deprecations 2026-04-29 14:47:05 +05:30
Prem Palanisamy b2b9ac5b4d fix: redis resource reads _APP_CONNECTIONS_CACHE with _APP_REDIS_* fallback
The dedicated \Redis DI resource (used by timelimit and the new Lock
class) was reading _APP_REDIS_HOST/PORT/PASS exclusively. Cloud
deployments configure cache via _APP_CONNECTIONS_CACHE URI form
(e.g. cache=redis://dragonfly:6379) and don't pass the legacy
_APP_REDIS_* vars to the appwrite container locally, so timelimit and
Lock both fail to connect outside production where Helm separately
injects the legacy vars.

Now prefers _APP_CONNECTIONS_CACHE when set (matching the cache pool
backend), falls back to _APP_REDIS_* for CE-style configs. No new env
vars introduced; both timelimit and Lock work in CE, cloud-local, and
cloud-production without compose changes.
2026-04-29 10:16:17 +01:00
Matej Bačo e75fc5b859 Add list scopes endpoint for Console 2026-04-29 10:08:31 +02:00
Jake Barnby 57b8305144 Merge pull request #12134 from appwrite/fix-realtime-span-exporter
added a guard to skip double import
2026-04-29 20:02:04 +12:00
Chirag Aggarwal a429fb5860 Merge branch '1.9.x' into bump-docker-base-1.2.0 2026-04-29 13:30:50 +05:30
Matej Bačo aca11ed073 Merge pull request #12170 from appwrite/feat-create-dynamic-keys
Feat: create dynamic keys
2026-04-29 09:58:22 +02:00
Chirag Aggarwal 86123c9e93 fix: update PHP extension path for xdebug cleanup in production 2026-04-29 13:27:04 +05:30
Chirag Aggarwal a58ea1123b chore: bump docker-base to 1.2.0 2026-04-29 13:21:17 +05:30
Prem Palanisamy 18a67e00d3 fix: refresh composer.lock content-hash 2026-04-29 07:55:38 +01:00
Prem Palanisamy e634145612 refactor: consolidate lock implementation into Lock class
Lock now uses Utopia\Lock\Distributed directly and owns the full
acquire/release/telemetry/error-reporting/fail-open/kill-switch logic
that previously lived in two inline DI factory closures.

Adds withKey($key, $fn, $ttl, $orFail, $waitTimeout) as a generic
escape hatch for non-platform key shapes (cache, queue, edge) and
unusual TTL/timeout requirements.

Per-attribute lock keys for set() so that an accessedAt bump and a
mcpAccessedAt bump on the same projects:{id} document don't compete.
Whole-document operations (run, runOrFail) keep document-level keys.

Removes the standalone distributedLock and distributedLockOrFail DI
factories — Lock is the single API.

request.php shrinks ~150 LOC; Lock.php grows to ~190 LOC.
2026-04-29 07:41:54 +01:00
Prem Palanisamy ce15eeb722 refactor: introduce Lock facade for platform-DB lock sites
Extracts the lock-key format and the lock+auth-skip+sparse-update pattern
into Appwrite\Locking\Lock with three methods:
  - set(collection, id, attribute=accessedAt, value=null) — throttled
    single-attribute write
  - run(collection, id, fn) — generic skip-on-contention
  - runOrFail(collection, id, fn) — block-then-409 for the deferred
    lost-update follow-up

Migrates the 4 call sites (router projects accessedAt + 3 in shared/api)
off the raw $distributedLock callable. Raw factories stay as escape
hatches for non-platform key shapes.
2026-04-29 07:17:04 +01:00
ArnabChatterjee20k dae9cbcf45 Merge pull request #12070 from appwrite/realtime-action-channels
Realtime action channels
2026-04-29 10:49:13 +05:30
Prem Palanisamy b15457bcca style: trim verbose comments on lock factories and call sites 2026-04-29 05:50:37 +01:00