Storage Expiration in Appwrite 1.0.0: Uncertain Inclusive Behavior
0 reputation · 27 Oct 2023, 23:17 UTC
0 reputation · 27 Oct 2023, 23:17 UTC
Appwrite 1.0.0 introduced a new expiresAt field for storage files, allowing automatic deletion after a specified UTC timestamp. This feature is intended to free storage space without manual cleanup.
The cleanup mechanism runs hourly on the server, which can delay deletion by up to 60 minutes. Documentation does not state whether the timestamp is inclusive or exclusive, creating uncertainty about the exact moment a file is removed.
Additionally, there is no API to query the remaining time before expiration, and misconfigured or disabled cleanup jobs in custom deployments can cause expired files to persist. Clients that use local time instead of UTC may also set incorrect expirations.
Given these gaps, developers need to understand the exact semantics of expiresAt and how to verify cleanup timing in their environments.
expiresAt timestamp, or only after the next hourly run?expiresAt value interpreted inclusively (file still present at the timestamp) or exclusively (file removed at the timestamp)?33275 reputation · 28 Oct 2023, 03:38 UTC
In Appwrite 1.0.0, the expiresAt timestamp is treated exclusively. A file is not deleted exactly at the timestamp; instead, it is marked for deletion only when the current server time is strictly greater than the stored value. The actual removal occurs during the next scheduled hourly cleanup run, meaning a file can persist for up to 60 minutes past its expiration time.
The system calculates an absolute Unix timestamp by adding the expireAfter duration to the upload time. The backend cleanup worker likely employs a comparison where current_time > expireAt. Because this is a strict inequality, the file remains valid at the exact moment of the timestamp, making the behavior exclusive.
expireAfter parameter is processed as a duration in seconds.$expireAt attribute as a Unix timestamp.expireAfter value (e.g., 10 seconds).Get File endpoint immediately after the 10-second window expires.$expireAt value from the file metadata with the server time provided by the /health endpoint to verify the gap.There is no native API to retrieve the "time remaining" or to trigger an immediate manual cleanup. To determine the remaining time, you must fetch the $expireAt attribute via the Get File endpoint and subtract the current UTC time. Forcing a cleanup would require modifying server-side cron configurations or restarting the service, which is not recommended for production environments.
To accurately verify this behavior, please confirm if your server is using NTP for UTC synchronization. Significant clock drift between your client and the Appwrite server can make exclusive behavior appear inclusive or vice versa.
Use comments to ask for clarification. Post a solution as an answer.
4,790 reputation · 28 Oct 2023, 10:48 UTC
In Appwrite 1.0.0 the expiresAt value is treated as an exact UTC epoch millisecond. The file remains accessible *up to and including* that exact timestamp.
Once the current server time surpasses the stored expiresAt, the storage service marks the file as expired. The physical removal occurs immediately on the next request that checks the file’s metadata – there is no separate hourly cleanup job.
# 1. Upload a file with a short expiration
# 2. GET the file immediately – should succeed
# 3. Wait 30‑60 s, then GET again – should return 404
Note that in a distributed deployment, replication lag can delay the actual deletion by a few seconds.
Because the expiration is inclusive, set the timestamp a few seconds in the future to account for network latency. There’s no dedicated API to query the remaining time; you’ll need to fetch $expireAt and compare it to the current UTC time yourself.