Skip to main content
Limits decide how much a user, an organization or a blob may hold, how far a single run may go, which blob types an organization may create, and how long finished work is kept. Every limit is one entry in one catalog. Each entry has a default, and an override can change it for one user, organization or blob. The API serves the values in force, and every refusal names the limit behind it.

Groups and ids

The catalog is divided into groups. platform, labelled Global, holds the limits that apply whatever a blob’s type. Every blob type has a group of its own, keyed by its type string, holding everything about that type — including whether an organization may create it at all. A limit’s id is <family>.<name>. The family is platform for a global limit, and the last segment of the type string for a type’s limit, so the limits of blobhub.compute.workflow are named workflow.*. Groups always come in this order. An error names a limit by its id; the limits routes return each limit inside its group.

Kinds

Every limit has a unit — count, bytes, seconds, days, flag or modules — and applies per one thing: a quota per holder, such as an org or a session; a ceiling per operation or run, such as a write, a query, a node or an execution.

How a value is chosen

  • Defaults first. A limit’s value is its default unless an override applies. A user, organization or blob with no overrides works on the defaults alone.
  • Overrides follow ownership. An override on a user applies to every organization that user owns. An override on an organization applies to every blob in it. An override on a blob applies to that blob alone. The nearest override wins, limit by limit.
  • Ownership is read on every request. Nothing is copied when a user, organization or blob is created, so an organization that changes owner follows its new owner’s overrides from its next request.
  • Work is limited where it runs. A session’s limits, and the limits of every execution in it, come from the session’s blob — not from the blob that holds the definition being run. workflow.running_executions_per_org counts against the organization of the session’s blob. A schedule’s fire runs in its target session, so the target’s limits apply. See Whose rules apply.
  • Each limit says where it can be overridden. The catalog’s Set on column lists the levels: user, org, blob. A blob type’s enabled entitlement, for example, can be set on a user or an organization, never on a single blob.
  • Some limits have a most permissive value. It comes from the platform itself — a cloud service quota, or a timeout BlobHub configures — and no override can go past it. For scheduler.min_interval_seconds less is more permissive, so an override can only raise it.
  • Fixed limits are published, not configurable. A limit whose Set on is fixed is a bound of the platform, the same for every account. It is in the catalog so that it can be seen next to everything else.
  • A list is replaced, not merged. An override of workflow.code_imports is the whole list for its level and everything below it.

Holdings

A quota counts what its holder holds now. The count lives on the holder’s own record and changes in the same step as the thing it counts: a create the API refuses takes no slot, and the step that removes a thing frees its slot.
  • A failed blob or revision keeps its slot. One whose creation ends in status failed holds its slot until it is deleted.
  • A blob’s first revision takes a slot too. It is counted when the blob is created, without being checked against the limit.
  • Deleting a holder deletes its counts. Deleting a session, a revision, a blob or an organization needs no separate release: the counts go with the record.
  • Session objects are counted by listing them. workflow.session_objects_per_session is checked only when a write would create a new alias, by counting the session’s objects. Two writes that create new aliases at the same moment can take a session one past its limit.
Where to read a holding:

Reading limits

Three routes return the limits in force, group by group, with each limit’s default, where its value came from, and — where the target being read is the holder — how much is held: The organization and blob routes need read access to their target. A user’s limits are readable by that user, and by anyone with admin standing on them, such as a service account’s owner. A type an organization has not enabled still appears, with its <family>.enabled entry false, so the organization can see what it would get.

When a limit is reached

A request refused by a limit answers HTTP 400 with the error limit_exceeded, except where a refusal has a code of its own: the blob-type gate’s invalid_blob_type and the fixed limits on session writes and graph queries, below. Each of these refusals carries a limit object naming the limit:
Key off error and limit.id. message is prose and may be reworded. A blob type answers with its own code. Creating a blob of a type the organization has not enabled answers 400 invalid_blob_type, and the body carries limit with the type’s entitlement, such as {"id": "orientdb.enabled", "value": false}. A type string that names no blob type answers the same code without limit. The fixed limits on session writes and graph queries answer with their own codes. A request past one of them is refused with HTTP 400 and the code below, and its body carries the same limit object — for graph_traversal_limit_exceeded, naming the cap that tripped: Inside logic.code, a write refused by workflow.session_objects_per_session raises LimitExceeded, carrying the limit object; see Code Component.

Limits during a run

create_execution resolves five limits once, and the execution keeps those values until it ends: workflow.processor_runs_per_execution, workflow.execution_seconds, workflow.code_run_seconds, workflow.code_imports and workflow.session_objects_per_session. A change to any of them applies to executions created afterwards. A schedule fire that a limit refuses is recorded in the schedule’s history with the status refused, carrying the same limit object. A refusal does not disable the schedule: a recurring schedule stays active and keeps firing. See Execution History.

Retention

  • Age counts from the end. An execution is past retention once it ended longer ago than its limit, and a run once it fired longer ago than its limit.
  • A daily sweep removes what is older. Anything past its retention is removed by the next sweep, so it can outlive its period by up to a day.
  • Only finished work. A running execution, a session and a definition are never removed by retention. Deleting a session still removes everything in it at once.
  • Removing an execution frees its slot. Each execution retention removes frees one slot in its session’s workflow.executions_per_session, so a long-lived session — one a schedule fires into every minute, say — stays below its limit.
  • null keeps forever. An override can set either retention to null.

Changing a limit

No API changes a limit: the routes above only read. Values other than the defaults are set by BlobHub. To ask for a different value, write to support@blobhub.io, naming the limit’s id, the user, organization or blob it should apply to, and the value. A fixed limit cannot be changed for one account, and no value goes past a limit’s most permissive one.

The catalog

Every limit, by group. Per is what one value applies to. Default is the value when no override applies. Most permissive is the furthest an override can go, — when the platform sets no bound. Set on lists where an override can be set; fixed means nowhere.

Global

Workflow

Scheduler

ONNX Model

Graph

NLP Dataset

An enabled entitlement gates creation only. An organization whose entitlement for a type is false keeps every blob of that type it already has.