Scale, limits and recovery
This page says what each part of the Crusoe AI Platform runs by default, what you can change, what changing it costs, what you cannot change and why, and what happens when something fails.
It is deliberately specific. Where we have not measured a recovery time, this page says so rather than giving you a number to plan around.
How to read the recovery times
| Label | Meaning |
|---|---|
| Measured | Observed on the beta platform, with the date and what was measured. |
| From configuration | Derived from a platform setting we control, so it is exact for the part it covers. It usually excludes container start-up, which we have not measured. |
| Not yet measured | We know the mechanism and not the duration. We will publish a figure when we have one. |
| Requires operator intervention | There is no automatic recovery. We do not publish a duration for these, because the dominant term is how long it takes a human to act. |
One thing to know before the per-service sections: if the machine running a workload fails hard
- power loss, kernel panic, no graceful shutdown - and that workload holds a persistent disk, the replacement cannot start until a platform operator releases the disk. This affects MemoryStore, VectorDB, Pub/Sub and the secret store. It is the longest outage on this page and it is the one we are fixing first. Workloads with no disk of their own - your agents, functions, serverless services and MCP servers - are not affected; they are simply restarted elsewhere.
Agents, functions and serverless services
Defaults
| Setting | Default |
|---|---|
| Minimum instances | 0 - the workload scales to zero when idle |
| Maximum instances | No ceiling on an agent or function that has never been configured; 10 for a serverless service |
| Concurrent requests per instance | Not set for an unconfigured agent or function, so the platform default applies; 80 for a serverless service |
| Instance size | medium - 1 CPU, 1 GiB memory |
| Request timeout | 300 seconds |
If you have never opened Compute settings, those are your values. Known issue: the compute-settings reference page currently states 10 / 80 / 60 for the first three rows; those are the serverless defaults, not an agent's or a function's. The table above is correct.
What you can change, and how
| Setting | API | CLI | Console | When it applies |
|---|---|---|---|---|
| Minimum instances | yes | yes | yes | next revision |
| Maximum instances | yes | yes | yes | next revision |
| Concurrent requests per instance | yes | yes | yes | next revision |
| Instance size (small/medium/large/xlarge) | yes | yes | yes | next revision |
| Custom CPU and memory | yes | yes | partly - the console offers limits only | next revision |
| Request timeout | yes | yes | yes | next revision |
Every change cuts a new revision. Your current revision keeps serving until the new one is ready, so a change that cannot start - for example a memory size below what your code needs - fails as a failed rollout rather than an outage. A rollout is given up on after 5 minutes on the agent and function path.
Cost of a change: no data loss. Your workloads hold no platform-managed storage. Requests in flight on the old instances when they are finally retired are cut for three of the four runtimes, because their shims do not yet stop accepting work and finish what they are holding when asked to shut down. Ruby is the exception and already does. Until the other three match it, treat a deploy as something that can end an in-flight request, whichever runtime you are on.
What you cannot change, and why
- Per-instance disk. Your container gets machine-local scratch space with a 2 GiB ceiling. There is no control for it and no persistent disk; write anything you need to keep to MemoryStore, VectorDB, Pub/Sub or a bucket.
- Anything above your project quota. A project is capped at 50 instances total, 20 CPU and 40 GiB of memory across everything in it. This is the limit that matters, and today no surface checks a scaling change against it: you can set a maximum of 100 instances and the platform will accept it, but your project cannot hold anywhere near that many. Treat the project quota as your real ceiling until we report a derived instance ceiling per size.
- Request timeout above 15 minutes. 900 seconds is the platform maximum. Some pages still say 3600; they are wrong. Separately, a request made through the platform's own buffered invoke path is cut at 60 seconds regardless of your setting.
Known control defects
- Opening the console's Compute settings dialog and pressing Apply without changing anything will change your settings, because every control is pre-filled with a platform default rather than your current value. Until this is fixed, set compute settings through the API or CLI, or set every field in the dialog deliberately.
- "Unlimited" for maximum instances means 10 for serverless services and MCP servers. It means genuinely unlimited for agents and functions. Do not rely on it either way.
- "Unlimited" for concurrent requests per instance is not applied on serverless services and MCP servers - the previous value stays in force.
If something fails
| Scenario | What you see | Data | Recovery | How long |
|---|---|---|---|---|
| One instance crashes | If more than one is running, nothing. If it was the only one, the request in flight fails. | none | automatic restart | Not yet measured |
| Deploy or config change | Nothing. Traffic stays on the current revision until the new one is ready. | none | automatic; a bad revision is abandoned | Give-up deadline 5 minutes (from configuration) |
| Planned machine maintenance | Instances on that machine are moved. A workload with a minimum of one instance has a gap while it restarts. | none | automatic | Not yet measured |
| Hard machine failure | Instances there stop answering; the platform restarts them elsewhere. No operator action needed - these workloads have no disk. | requests in flight are lost | automatic | Not yet measured |
| Platform control plane down | Running workloads are unaffected. Deploys, edits, logs and metrics stop. | none | automatic | Not yet measured |
| Idle | A scale-to-zero workload has no instances; the next request pays a cold start | in-memory state only | automatic | ~90 seconds to drain (from configuration); cold start not yet measured |
MCP servers
Defaults
One warm instance (an MCP server never scales to zero, whatever the dropdown, the CLI help or the docs currently say), a ceiling of 10, 80 concurrent requests per instance, medium size, 300 second request timeout.
What you can change, and how
Compute settings are available in the API and the console. They are not applied when you save
them. A saved change is stored and takes effect the next time you publish a tool, which rebuilds
the server. There is no platformctl mcp config command yet.
Until both are fixed: change compute settings, then publish a tool to apply them.
What you cannot change, and why
- Minimum instances cannot be 0. An MCP server is reached directly by name with no wake-up path in front of it, so a zero floor would mean every tool call is refused. The platform raises any value below 1 to 1. It should refuse it instead, and will.
- Per-instance disk - as for agents above.
If something fails
Same shape as agents and functions: stateless, no disk, automatic restart, no operator action needed on a hard machine failure. Your tool source, version history and image digests are held by the platform and survive any instance loss. Recovery times: not yet measured - there is a window after a restart during which the server has no instances and tool calls fail, and we have not measured it.
MemoryStore
Defaults
| Setting | Default |
|---|---|
| Instances | 1 - there is no replica today |
| Size class | small, the smallest of the three. What each class allows is in the one table on the MemoryStore overview |
| Persistence | on, with a 2 GiB disk - sized at create, independently of the size class |
Durability (persistence.fsync) | everysec - up to about one second of acknowledged writes can be lost if the machine dies |
| Eviction policy | noeviction - writes fail when the dataset is full, reads keep working |
| Credential lifetime | 90 days, with a 24 hour renewal overlap |
What you can change, and how
| Setting | API | CLI | Console | When it applies |
|---|---|---|---|---|
| Size class | create, then PATCH | create, then update (--size-class) | create, then Resize on the instance page | any time - one restart |
Durability (persistence.fsync) | create, then PATCH | create, then update (--fsync) | Resize on the instance page | any time - one restart |
| Persistence on/off | at create | at create | at create | create only - a later change is refused |
| Disk size | at create | at create | at create | create only - a later change is refused |
| Eviction policy | at create | at create | at create | create only |
| Engine version | at create | at create | at create | create only |
| Rotate / renew the credential | yes | yes | yes | any time |
There used to be no update path of any kind, so the only way to give an instance more memory was to delete it and create another one - which threw the data away. Size class and durability are the two things you can now change on an instance that already exists.
What a change costs. A change restarts the instance once; sending the values it already has changes nothing and does not restart it. Connections drop and have to reconnect. What the restart costs your data depends on one setting:
- Persistence on (the default): the disk follows the instance and it reloads the append-only file on the
way back up, so a graceful restart like this one costs nothing. That is a statement about this restart,
not about every failure - if the machine dies mid-roll, the
everysecwindow below still applies. - Persistence off: there is no disk. The instance comes back empty. Same restart, opposite outcome, and the API's response says which one you are getting before you wait for it.
Measured at 27 seconds back to serving on the beta platform with a small store, so plan for about 30 seconds. A large dataset takes longer to load back from disk; that one is not yet measured.
The console. The instance page has a Resize button, next to Refresh. It carries both controls and nothing else, because everything else on this list is refused after create. The dialog reads the instance when you open it, so it shows what the instance has now rather than what the page was last polled for - a level you set from the CLI is what the dialog opens on. The instance page's Configuration card lists the durability level too, which it did not before. Three things the dialog does deliberately:
- Picking a smaller class says so before you press Apply, along with the fact that the platform checks the change against what the instance is actually holding and declines a shrink that will not fit.
- Durability is only offered when persistence is on. With persistence off there is no append-only file to flush, and the API refuses the field.
- The disk size and the persistence switch are not in the dialog at all, and it says why underneath.
Resize is admin-only, because PATCH is. A project member sees the instance page without the button
rather than a 403 they could not have predicted.
What you cannot change, and why
- The disk size. A
persistence.sizein an update is refused with400: a disk cannot be grown or shrunk in place on this platform. If you need a bigger one, create a new instance with the size you want and migrate to it. The refusal replaces a defect: the platform used to accept the edit, never apply it, and then report the new number back to you as though it had - so the only way to find out was to run out of room you thought you had bought. Edited directly on the underlying resource it is refused now too and the instance reports Degraded - but the number you typed is still echoed back until you put it back, so trust the size you set at create. The disk is also independent of the size class: growing the class does not grow the disk. - Persistence on or off. A
persistence.enabledin an update is refused with400for the same underlying reason: the disk is attached when the instance is created, and an instance that is already running cannot have one added or taken away. Create a new instance and migrate. - Durability on an instance that has persistence off. A
persistence.fsyncin an update is refused with409: there is no append-only file to flush, so the setting would change nothing, and accepting it would report back a durability level the instance does not have. Create a new instance with persistence enabled and migrate. - A size class shrink that lands at or below what the instance is holding right now. The refusal is a
409naming both numbers: what the instance is using, read live from the instance at the moment you ask, and what the new class would allow. (What each class allows is in the one table on the MemoryStore overview, and is deliberately not restated here.) An equal pair is refused too - an instance sitting exactly at the new ceiling fails its next write, which is the state the guard exists to avoid. This one is worth understanding rather than working around, and it is refused whatever your eviction policy is. With the defaultnoeviction, an instance that woke up over its limit would not shed anything to fit: it would keep every key, keep answering reads, and fail every write - a failure that looks like your code being broken rather than like an outage. Withallkeys-lru, or any other eviction policy, it would do the opposite and throw keys away until the dataset fit - data you did not ask to lose. Delete keys or shrink your working set first, then change the class. If the live usage cannot be read at all - the instance is provisioning, restarting, or unreachable - the shrink is refused as well, and says which. Guessing is how you get back the silent version of this bug. - The number of instances. One instance serves every connection, and there is deliberately no control asking for more. Replication needs a way for clients to find the writable instance, a way to promote a survivor, and a way to keep traffic off one that is not ready to take it. None of those exist here yet, and a setting that only ever accepts 1 would read as support that is not there. Anything you read elsewhere about the platform managing replication for MemoryStore is wrong and is being corrected.
- There is no backup, snapshot or export. If the disk is lost, the data is gone. Treat MemoryStore as a cache or a session store you can rebuild, not as a system of record.
Durability
persistence.fsync sets how long an acknowledged write may sit in memory before it is on disk. It
only means anything while persistence is on: with persistence off there is no disk, and a restart
loses everything in the instance.
| Value | What an acknowledgement means | What it costs |
|---|---|---|
everysec (default) | The write is handed to the machine to write out, and is on disk within about a second. A restart of the instance alone keeps it; if the machine dies, up to about one second of acknowledged writes can be lost. | Nothing extra. This is what every instance has run with so far. |
always | An acknowledged write is on disk before we acknowledge it. | Every write waits for the disk before it is answered. We have not measured what that costs on this platform, so treat it as a real and unmeasured latency cost rather than a free upgrade, and measure your own workload before you depend on the number. |
Neither value means "nothing can ever be lost", and always least of all, because its promise is
narrow on purpose: it is about one instance and its own disk, at the moment of the acknowledgement.
It says nothing about losing the disk, deleting the instance, or a machine failure that strands the
disk where nothing can reach it. There is no replica and no backup behind it, so each of those is
still a total loss. always protects you from a crash. It does not protect you from the rows in the
table below that say the data is gone.
If something fails
| Scenario | What you see | Data | Recovery | How long |
|---|---|---|---|---|
| You change the size class or the durability setting | The instance restarts once; connections drop and reconnect. Sending the values it already has restarts nothing | persistence on: none - the disk follows the instance and it reloads the append-only file. Off: everything - there is no disk, and it comes back empty | automatic | About 30 seconds (Measured, beta: 27 seconds on a small store) |
| The instance crashes or restarts | Connections drop; reconnects are refused until it is back | persistence on: none, if the machine itself is still alive. If the machine died with it: with everysec, up to about a second of acknowledged writes; with always, none of the writes already acknowledged, provided the disk survives. Off: everything | automatic | Measured (beta): 27 seconds from a deliberate instance delete to serving again, on a small store, with the disk following to a different machine and its contents intact. A restart with a large dataset takes longer to replay; not yet measured. |
| You change the credential, or it expires unrenewed | The instance restarts and old passwords stop working | as above | renew before expiry; rotation is immediate | Same as a restart |
| Planned machine maintenance | The instance is unavailable while it moves | none with persistence on; everything with it off | automatic | Not yet measured (disk detach and reattach dominate) |
| Hard machine failure | The instance stays down. The disk is still attached to the failed machine and the replacement cannot start. | none - the data is intact and unreachable | Requires operator intervention | No duration published |
| Disk loss | The instance returns empty | total and permanent | recreate and repopulate from your own source of truth | n/a |
| The platform control plane is down | Your instance keeps serving. Create, delete, update, rotate, list, stats and the console page stop working. | none | automatic | Not yet measured |
VectorDB
Defaults
One shard, one replica, the platform embedding width, payload in memory, no quantisation. One replica is also the ceiling today, because the platform has room for a single copy.
What you can change, and how
| Setting | API | CLI | Console | When |
|---|---|---|---|---|
| Payload on disk | yes | yes | yes | applied in place, no downtime, data untouched |
| Replicas | yes | yes | yes | bounded by how many copies fit - see below |
| Shards, dimensions, vector storage, quantisation | at create | at create | at create | create only, refused afterwards with a reason |
About replicas: the field accepts 1 to 8 and the platform runs a single vector engine
copy, so a second copy has nowhere to live. Until now the number was accepted anyway, stored, and
reported back to you unchanged. The reconcile loop could not catch it either: the figure it compared
against was the replication factor the engine had been asked for, read back out of the index's own
configuration, so a request for 3 converged contentedly at 3 while a single copy was all there was.
Two things have changed.
- A
replicasthe deployment cannot place is refused at request time, on create and on update, with a409naming the real number. Today that number is one, so1is the only value that is accepted. Asking for1is never gated on the reading - one copy needs no second place. Asking for more when that number cannot be read is refused rather than accepted on a guess, which is the rule the MemoryStore shrink guard already follows. - The index reports an achieved replica count (
achieved_replicas), read from its real shard placement, beside thereplicasthat was asked for. Where the two ever disagree, the achieved number is the one that is about your data. The CLI prints them as one value -1 requested, 1 achieved- so the requested number never appears on its own.
The field is bounded rather than withdrawn, because the bound is the deployment's: it lifts by
itself when the platform can hold more copies, and nothing here should be read as saying
that has happened. Nothing about the console changed - it still offers the field, and the refusal
reaches it because the check is in the API. The customer documentation that described replicas as
"how many copies exist" has been corrected.
What you cannot change, and why
- Shards, vector width, on-disk storage and quantisation are fixed at create. Changing any of them would move or re-encode every point. All three surfaces refuse a change and say so; to change one, create a new index and re-index. This is the refusal behaviour we want everywhere.
- There is no per-project limit on index count, point count or collection size, and all projects share one storage volume. There is also no way to see how much of it is left. Until we add a quota, a single large index can affect other projects.
If something fails
| Scenario | What you see | Data | Recovery | How long |
|---|---|---|---|---|
| The engine restarts, or the platform upgrades it | Every query, insert and delete fails for every project - there is one engine instance | none committed | automatic | Not yet measured; it reloads its index segments on start, so it scales with index size |
| Planned machine maintenance | Same total interruption | none | automatic | Not yet measured |
| Hard machine failure | Same, indefinitely | none - intact and unreachable | Requires operator intervention | No duration published |
| Disk or zone loss | Indexes empty or missing | everything since the last nightly snapshot | operator restores per collection | RPO: up to 24 hours (nightly snapshot, 7 kept). Restore time not yet measured |
| You change replicas | 1 is accepted and nothing changes behind the number; anything higher is refused, naming how many fit | none | n/a | n/a |
Correction to existing docs: the quickstart says deleting an index has "no undo and no snapshot". The platform does hold up to seven nightly snapshots of every collection. Restoring one is an operator action, not a self-service one - but ask.
Pub/Sub
Defaults
| Setting | Default |
|---|---|
Topic backlog budget (max_bytes) | 16 MiB |
| Message age limit | none |
| Acknowledgement deadline | 30 seconds |
| Maximum delivery attempts | 5 |
| In-flight messages per subscription | 1000 |
| Project backlog budget | 1 GiB, shared by all your topics |
| Topics per project | 100 |
What you can change, and how
Backlog budget, age limit, acknowledgement deadline, delivery attempts and in-flight limit are all editable at any time, at the API, the CLI and the console. Changes apply without recreating the topic and without losing messages, within about five minutes.
One edit is gated, and it is the one that could cost you data: lowering a topic's backlog budget
(max_bytes) to at or below what the topic is currently holding is refused, not applied. See
below. Raising it is not gated on anything but the project budget.
What you cannot change, and why
- Replication. Every message is committed to more than one storage instance before you are told it was accepted. This is a property of the platform, not a per-topic choice, so there is no control for it - deliberately.
- Partitions. Every topic is non-partitioned, which gives total ordering. Partitioning cannot be undone on a live topic, so we have not offered it yet.
- The project backlog budget. It is the same 1 GiB for every project and there is currently no way to raise it. Known defect: the error you get when you exhaust it tells you to ask your platform operator to raise it. There is no such control, and a manual change is reverted automatically. We are either building the override or changing the message.
What can lose messages
-
Lowering a topic's backlog budget below its current backlog used to discard the oldest messages at every surface, with no warning and no confirmation. It is now refused with a
409that names both numbers - what the topic is holding and the ceiling you asked for - and what the change would have done to that topic, because the outcome follows its owndiscardsetting rather than being the same everywhere:discardWhat lowering below the backlog does old(the default)The broker drops the oldest unacknowledged messages until the backlog fits. Immediate and permanent; nothing is dead-lettered. newNothing is dropped; publishes start failing until consumers drain the backlog below the new ceiling. Dropping the oldest messages is a legitimate thing to want, so there is an explicit override: repeat the call with
?allow_discard=true(--allow-discardin the CLI) and it goes through, with that consequence. It is the same shape as?cascade=trueon project delete - refused by default, explicit when you mean it, never inferred. A topic that is not reporting live figures yet is refused as well, naming the state it is in rather than guessing: on a topic that is not ready, abacklog_bytesof0means unknown, not empty. The same override covers that case, so an unreadable topic is not un-shrinkable forever.The console has no override yet. Its edit dialog sends the plain request, so a lowering that would cost messages is refused there with nothing to click through; make that change from the API or the CLI. Read the backlog first either way:
platformctl pubsub usagehas aBACKLOGcolumn, and the topic itself reports it asstats.backlog_bytes. That is the same reading the check makes, so there is no second number to reconcile. -
Lowering the maximum delivery attempts, or reaching it, drops the message unless the subscription has a dead-letter topic. Set one if the messages matter.
Also: exclusive and failover push subscriptions are accepted and do not work reliably in the
current deployment. Use shared for push subscriptions until this is fixed.
If something fails
| Scenario | What you see | Data | Recovery | How long |
|---|---|---|---|---|
| A delivery worker restarts mid-delivery | A push target may receive the same message twice | none - at-least-once, duplicates rather than loss | automatic | Worst case about 50 seconds before the next attempt (from configuration) |
| A broker restarts | A brief interruption while topics move to the survivors; clients reconnect | none committed | automatic | Not yet measured |
| A storage instance is lost | Nothing - committed messages are on more than one of them | none | automatic re-replication | Not yet measured |
| Two of three metadata instances lost | Pub/Sub is fully unavailable | none | operator | Not yet measured |
| Hard machine failure holding a storage or metadata instance | Degraded but serving | none from the first one | Requires operator intervention to release the disk | No duration published |
| A topic is deleted outside the platform | It comes back empty | every message in it | automatic recreate | Within 5 minutes (from configuration) |
| The management API is down | Publishing and consuming continue. Creating and editing topics stops. | none | automatic | Not yet measured |
Agent Guardrails
Defaults
Three service instances; per-agent policy with per-tier time budgets of 50 / 400 / 500 / 1500 ms, a 64 KiB text ceiling per check, and verdict retention set to 30 days.
What you can change, and how
Policy fields - the tiers that run, their time budgets, the text ceiling, the fail behaviour and retention - are editable at the API, the CLI and the console, per agent and per project. Changes take effect on the next request; nothing restarts.
The service's own instance count is not a customer setting and is not offered anywhere.
The one thing to plan around
If the guardrail service is unavailable, an agent on the standard or strict preset refuses
every turn. The end user receives an ordinary answer whose text is the refusal sentence. This is
deliberate - the pattern tier fails closed in both shipped presets - but one page currently says the
opposite for standard. The correct behaviour is:
| Preset / setting | Behaviour when the service is unreachable |
|---|---|
standard, strict | every guarded turn is refused |
fail.pattern: open | flagged and allowed through, with your original text preserved |
mode: monitor | flagged and allowed through |
off | unaffected - no call is made |
If availability matters more than enforcement for a given agent, monitor mode is the documented
way to get it.
Known control defects
- Retention is accepted and not enforced. Setting
logging.retention_daysis validated, accepted and echoed back on all three surfaces, and the console says older records are deleted for you. Nothing deletes them. Verdict records persist until the project is deleted. If you set a retention period for a data-handling requirement, it is not being met. - Rate limiting is documented and not implemented. There is no
429with arate_limitedcode from the guardrail service; the only rate limit you can hit is the platform's general one. Client code branching on that code will never match. - The text ceiling is 65,536 bytes, not the 1,048,576 some pages state. Higher values are refused by the API and clamped by the console.
If something fails
| Scenario | What you see | Data | Recovery | How long |
|---|---|---|---|---|
| One service instance fails | Nothing for most traffic; turns in flight on that instance resolve locally, which under standard means a refusal | verdict records queued on that instance are dropped | automatic | A hung instance leaves rotation after about 30 seconds (from configuration); a crashed one immediately. Return to service: not yet measured |
| Platform upgrade | Normally nothing | as above | automatic | Not yet measured |
| The platform database is down | Checks keep working and are still enforced. The verdict feed and the 24-hour summary return an error and new decisions are not recorded. | the record of what was blocked during the outage is permanently lost and is never backfilled | automatic for new traffic | Recording resumes when the database returns, within 5 minutes in the worst case (from configuration) |
| The safety model is unreachable | Under standard: requests continue, each flagged. Under strict: refused. | none | automatic | Immediate on the next request |
| The whole service is unavailable | See the table above | none - policies, references and past verdicts are untouched | restore the service | Detection per turn is about 3.2 seconds (from configuration); restoration time not yet measured |
Secrets Manager
Defaults
Three storage instances behind one endpoint, values up to 64 KiB, issued read tokens valid for 5 minutes by default and 60 minutes at most, daily snapshots.
What you can change, and how
Create, read, version, reveal and delete secrets, and issue short-lived read tokens, at the API, the CLI and the console. The token lifetime is a per-request field. If you ask for more than the maximum, it is silently reduced - the response reports the lifetime you actually got, and nothing else tells you it was changed. Compare the returned value with what you asked for.
Nothing about the store's own size or instance count is a customer setting.
What you cannot change, and why
- The 64 KiB value ceiling is a platform constant.
- How many versions of a secret are kept. The overview page says existing versions are retained unless explicitly deleted. The platform does not currently configure version retention at all, so what you actually get is the storage engine's built-in behaviour. We are measuring it, setting it explicitly, and correcting that sentence. Until then, do not rely on unlimited version history.
What breaks when the store is unavailable
This matters more than the recovery time, because the answer is not "everything":
| What you are doing | Affected? |
|---|---|
| A workload reading a secret bound to an environment variable | No. The value was written into the workload when it was deployed. |
| A workload calling the secret API at runtime | Yes - the call fails closed. |
| Listing your secrets | No - that path does not need the audit database. |
| Viewing one secret | Mostly no; the "used by" field is silently omitted, so an empty list may mean "we could not check". |
| Revealing a value, applying a binding, deploying something that needs a reveal | Yes - these need the audit database as well, and refuse rather than returning a value they cannot record. |
If something fails
| Scenario | What you see | Data | Recovery | How long |
|---|---|---|---|---|
| A non-serving instance restarts | Nothing | none | automatic, including re-unsealing | At least 30 seconds after it answers (from configuration); the upper bound is not yet measured |
| The serving instance is lost | Every secret route fails until another one takes over | none committed | automatic | Not yet measured |
| All three restart together | Every secret route fails until they are unsealed automatically | none - the data is intact | automatic | At least 30 seconds per sweep (from configuration); not yet measured |
| Hard machine failure | Degraded; the lost instance does not return | none while the others hold | Requires operator intervention | No duration published |
| Total loss | Everything | up to 24 hours since the last snapshot | operator restores from the snapshot | RPO up to 24 hours. Restore time has never been rehearsed - not yet measured |
| The platform database is down | Reveals and bindings fail; reads and writes of secret values continue | none | automatic | Bounded by the database's own recovery |
Object storage buckets
Buckets are not hosted by this platform. They live in your own Crusoe Cloud account, are billed to you, and follow that account's durability, retention and capacity rules. The platform provides a thin management view: list, create, inspect and delete, plus bucket-triggered functions.
What you can change
Name and region at create. Region cannot be changed afterwards - there is no update route at all; to move a bucket, create a new one, copy the data yourself and delete the old one.
Limits
- The platform imposes no bucket size limit and no bucket count limit. Any limit you hit is your Crusoe Cloud account's. We cannot currently tell you what it is or how close you are.
- Bucket listings are cached for 45 seconds, so a bucket created directly in your cloud account can take that long to appear here.
- A listing resolves the storage endpoint for at most 60 buckets per page. Beyond that the endpoint column is blank and the response says how many were skipped; the console shows a note, the CLI currently does not.
- A management call to your cloud account is given up on after 60 seconds.
Deleting a bucket
Deleting through this platform deletes the bucket and its contents in your cloud account. There is no soft delete, no recycle bin and no platform-side backup of your buckets. Recovery, if any, is whatever your cloud account offers. Deletion is available in the API and console; the CLI can create but not delete.
Known defect
Most errors from your cloud account arrive as a generic "the call failed" with advice to retry. A duplicate bucket name, an invalid name, a non-empty bucket on delete or an account limit are all your request, and retrying will not help. We are mapping these to readable errors and adding name validation before the request is sent.
If something fails
| Scenario | What you see | Data | Recovery |
|---|---|---|---|
| Your cloud account's API is unreachable | Management calls fail. Workloads reading and writing buckets directly are unaffected - they do not go through this platform. | none | automatic when it returns; listings may be up to 45 seconds stale |
| The project's cloud credential is removed | Bucket management stops; bucket-triggered functions stop firing within about 60 seconds | none - buckets and contents are untouched | reconnect the credential; triggers resume on the next poll |
| The platform's control plane is down | Bucket management stops | none | automatic |
When the platform's own control plane is unavailable
The management API, the console and the docs site run with several instances each and survive losing one. What you should expect:
| Scenario | Your running workloads | Management |
|---|---|---|
| One control-plane instance fails | unaffected | unaffected |
| Platform upgrade | unaffected | brief connection resets possible on in-flight management calls |
| The platform database is unavailable | unaffected - agents, functions, serverless services, MemoryStore, Pub/Sub, the vector store and published endpoints keep serving | the management API becomes unavailable within about 15 seconds (from configuration) and returns when the database does |
| The image registry is unavailable | running workloads unaffected | every deploy fails, and a scale-to-zero workload whose image is not cached locally cannot start. Budgeted at 15 minutes; this budget has not been verified by a measured restore |
| A deploy is interrupted by a control-plane restart | the running version keeps serving | the workload stays marked as building for up to 30 minutes, and a retried deploy or a delete is refused during that window. It clears itself. Some pages currently tell you to re-issue the deploy; that returns an error until the window expires. |
Backups, in one place
| What | When | Kept | Recovery point | Recovery time |
|---|---|---|---|---|
| Platform database (your projects, members, keys, bindings, audit) | daily, 02:00 UTC | 7 | up to 24 hours | never rehearsed - not yet measured |
| Vector collections | daily, 02:20 UTC | 7 | up to 24 hours | not yet measured |
| Secret store | daily, 02:40 UTC | 7 | up to 24 hours | never rehearsed - not yet measured |
| MemoryStore | none | - | - | - |
| Pub/Sub messages | none (messages are replicated live, not backed up) | - | - | - |
| Your buckets | your cloud account's policy | - | - | - |
Copies are held on the same platform-managed storage. A copy held off the platform is not enabled by default. If your data has a recovery requirement we have not met here, tell us before you rely on it.