Background jobs
Which work XICBOT does in the background, in what order, how often a failed job is retried and how long jobs are kept.
In plain language
Some work takes longer than a single request. One example is reading a website. Such work runs in the background. You get an answer right away, and the work follows later. This page lists the kinds of jobs. It shows in which order they get their turn. It says what happens after an error. And it says how long a job is kept.
All documentation topics
Some work takes longer than a single request: reading a website, recalculating knowledge, syncing a shop, delivering emails and webhooks, running an assistant's check questions. XICBOT accepts such work as a background job, answers right away and does the job afterwards. This page covers which jobs exist, in what order they get their turn, what happens when one fails and how long a job is kept.
What runs in the background
Every job has a type (task), a lane and a priority. The lane follows from the type; the priority is set by whatever creates the job. A lower number means an earlier turn.
| Type | Purpose | Created by | Lane | Priority |
|---|---|---|---|---|
source.ingest | Read a website source for the first time | Creating a source of type website, in the app or through the API with an API key | index | 3 |
source.refresh | Read a website source again | Re-read, optionally with Rebuild completely (3); the daily refresh run for website sources that are due, and the refresh of a stale source that an answer draws on (7) | index | 3 or 7 |
knowledge.rebuild | Recalculate enrichment and vectors of the sections | Creating any source in the app other than a collection of question-answer pairs or through the API with an API key, Re-read, reading the website during a setup and POST /api/v1/knowledge/embed (5); an automatic refresh (8) | index | 5 or 8 |
setup.propose | Build a setup proposal from your website | Starting a setup | index | 3 |
assistant.check | Run through an assistant's check questions | Start acceptance run for an assistant, see Test dialog and acceptance | index | 5 |
shop.sync | Pull the catalogue from a connected shop | Manual sync with Sync now (5); scheduled hourly sync for active accounts with an active connection and shop integration in their plan (7) | index | 5 or 7 |
webhook.deliver | Deliver an event to a webhook | Every event an active webhook subscribes to, one job per webhook, provided the plan includes the feature for keys and webhooks | default | 3 |
mail.send | Send an email | Handing a conversation over to a person (3); other emails (default 5) | default | 3 or 5 |
report.weekly | Build an account's weekly report | Weekly schedule on Monday, one job per active account that has not unsubscribed from the weekly report | default | 7 |
When the daily refresh run, the hourly shop sync and the weekly report start is covered in Schedules.
Lanes and order
The index lane carries the long runs: reading sources, recalculating, setup, acceptance runs and shop sync. The default lane carries everything else, namely emails, webhooks and the weekly report. The split is meant to keep an email or a webhook from waiting minutes behind a source being read.
On each lane XICBOT takes the waiting job with the lowest priority number and, with equal numbers, the older one. A job sitting out its wait after a failed attempt is skipped until that wait is over.
| Priority | Jobs |
|---|---|
| 3 | Creating a website source, Re-read, setup, webhook delivery, email for a handover |
| 5 | Recalculating after a source is created or re-read, after a setup has read the website and via POST /api/v1/knowledge/embed, acceptance run, manual shop sync, other emails |
| 7 | Daily refresh run, refresh during an answer, scheduled shop sync, weekly report |
| 8 | Recalculating after an automatic refresh |
Job states
| State | Meaning |
|---|---|
pending | Waiting for its turn, including between two attempts. After a failed attempt its reason is in error. |
running | Being processed right now. The attempt has already been counted and the error text of an earlier attempt is cleared. |
done | Finished. The outcome is in result and the error text is cleared. |
failed | Failed for good: the last attempt went wrong or the job expired. The reason is in error. |
Retries after a failure
A job has up to three attempts. An attempt counts as soon as XICBOT picks the job up. If it fails and attempts are left, the job goes back to pending with a wait. If the third attempt fails, the job stays on failed for good. The error text remains on the job, cut to 500 characters. A job that has failed for good raises a critical notice with the source queue for operations; see Notices.
| After | Wait on default | Wait on index |
|---|---|---|
| the 1st failed attempt | 30 seconds | 2 minutes |
| the 2nd failed attempt | 2 minutes | 10 minutes |
| the 3rd failed attempt | no further attempt, failed | no further attempt, failed |
What counts as a failure
- Reading a source: if the source is not ready after the run, the attempt has failed. Every failed attempt triggers the webhook event
knowledge.failed; a successful one triggersknowledge.indexedwith the number of documents and sections. If the build fails after fetching, the source shows not indexed with the reasoningest_failed, and the existing content keeps answering. If the source has been deleted in the meantime, the job counts as done without being carried out; its result carriesskippedwithsource_deleted. - Acceptance: if the check run has been deleted along with its assistant, the job counts as done without being carried out (
skippedwithrun_deleted). If the job fails for good, is recovered as failed or expires, the check run shows stopped with the reasonjob_failed; see Test dialog and acceptance. - Webhook: only a response with a 2xx status counts as delivered. XICBOT does not follow redirects (3xx); they count as a failure, as does a response that takes longer than 8 seconds. If the webhook has been deleted or switched off in the meantime, or the plan no longer includes the feature for keys and webhooks, the job counts as done without delivery.
- Switching off a webhook: after 20 failed delivery attempts in a row XICBOT switches the webhook off; every retry counts. A successful delivery resets the counter.
- Email: an email already recorded as sent does not go out again on a further attempt. A handover email is no longer sent if the conversation has been deleted in the meantime.
- Shop sync: a failed fetch from the shop does not make the job fail: it ends on
done, and itsresultcarriesok: falsewith the reason undererror. The existing catalogue stays, the error is shown on the connection, and the next scheduled sync tries again.
Webhook signatures, headers and events are covered in API keys and webhooks, connecting a shop in Catalogue, basket and shop connection.
Stuck and stale jobs
A job that has been marked as running for more than an hour, or whose worker process is no longer running, counts as orphaned. XICBOT resets it when the background service starts and during the hourly maintenance: to pending while attempts are left, otherwise to failed. The error text gives the reason; for the one-hour limit it reads „seit mehr als 3600 Sekunden ohne Fortschritt“ (more than 3600 seconds without progress).
A job that is still waiting or running 7 days after it was created expires during maintenance. It ends on failed with the error expired and is not carried out further; its end is taken as 7 days after creation. If an email was still waiting to be sent with it, that email counts as failed with the note „Versandauftrag nach 7 Tagen abgelaufen“ (send job expired after 7 days).
Duplicate jobs
In several places XICBOT creates no second job while one of the same kind is open, that is waiting or running:
- Re-read on a source that already has an open intake or refresh job, including the first intake of a new website, takes over that job; the response carries
already_open: true. If you tick Rebuild completely while a job without a rebuild is still waiting, the job picks up the rebuild. If it is already running, the API answers 409 withrefresh_runningand the app reports “A build is running or queued for this source. Please try again afterwards.” When an open job is taken over, the recalculation is still queued in addition. - The daily refresh run and the refresh during an answer skip a source that already has an open intake or refresh job.
POST /api/v1/knowledge/embedtakes over an open recalculation job of the account, even one for a different source; asource_idyou pass then has no effect.- A manual sync takes over an open sync; the app then reports “A sync is already waiting.”, otherwise “The sync has been queued.” If no sync is open, a lock applies until 15 minutes after the last manual request: response 429 with
sync_too_soon,retry_after(seconds) and theRetry-Afterheader. The app then reports “A manual sync is possible at most every 15 minutes. The regular sync continues independently.” - The scheduled hourly sync skips an account that already has an open sync.
- The weekly schedule skips an account that already has a weekly report job this week or has already been sent the report.
- An acceptance run for an assistant that already has an open run returns that run, provided it was created less than an hour ago.
- While a source has an open intake or refresh job, no earlier version of that source can be restored: response 409 with
refresh_running.
Tracking jobs through the API
When a request creates a job, the API answers with 202 and a job object holding id, status and task: when creating a website source, for POST /api/v1/knowledge/sources/{id}/refresh and for POST /api/v1/knowledge/embed. The manual sync via POST /api/v1/catalog/shop/sync returns the ID as job_id, together with already_pending; it requires the Administration role. GET /api/v1/knowledge/jobs/{id} returns the state of each of these jobs, including the sync.
GET /api/v1/knowledge/jobs/{id}
Returns the state of a job under job: id, task, status (pending, running, done, failed), attempts (number of attempts started), error (reason of the last failure; empty while an attempt is running and after success), result (outcome of a finished job) and finished_at (end time for done and failed in ISO 8601 format, otherwise empty). An ID that does not belong to your account returns 404 with not_found.
- Authentication
- Signed in, confirmed email address, any role
POST /api/v1/knowledge/sources/{id}/refresh
Reads a website source again and then queues the recalculation. The optional field rebuild (true or false) rebuilds every section, even where the text has not changed. If an intake or refresh job is already open for the source, the request takes it over. If it asks for rebuild while that job is already running without a rebuild, the API answers 409 with refresh_running. Returns 202 with job and already_open; if an open job was taken over, job names that job, and its task can then also be source.ingest. A source that does not belong to your account returns 404 with not_found; a source that is not a website returns 422 with website_only.
- Authentication
- Signed in, confirmed email address, Edit role or higher
- Rate limit
- 20 per minute per signed-in user, shared with creating sources, restoring a version and
POST /api/v1/knowledge/embed
POST /api/v1/knowledge/embed
Queues the recalculation of enrichment and vectors. Without source_id the job covers all sources of the account; with the optional source_id (an ID in UUID format) only that source. Only sections without a current state are calculated, at most 20000 per job; whatever is left is reported as remaining in the job result. If a recalculation job is already open for the account, the request takes it over. Returns 202 with job, already_open and the state at the time of the request across all sections of the account: vectors with chunks, embedded and pending, enrichment with chunks, enriched and pending. In the app, Build spread triggers this.
- Authentication
- Signed in, confirmed email address, Edit role or higher
- Rate limit
- 20 per minute per signed-in user, shared with creating, refreshing and restoring sources
How long jobs are kept
- Once a job is done or has failed for good, XICBOT cuts its data down to references such as source, run, account, email template, delivery, webhook and event. Recipient, email content and the content of a webhook message are dropped; if anything was dropped, the job carries the marker
reduced. - Done and failed jobs are deleted 14 days after they end. Until then type, times and error text remain.
- When you delete a conversation, the related email and webhook jobs go with it. Open webhook deliveries of the events
lead.createdandappointment.requestedstay, because they report a case. - Your account's jobs are part of the data export. Under Legal and data, the Stored data table counts them in the Background jobs row. They are deleted together with the account.
Retention periods for conversations and other data are in Retention and deletion, export and account deletion in Privacy and legal.
Frequent questions
Why is my website source not ready yet after creating it?
It is being read in the background. Creating it answers right away, and the job gets its turn on the index lane by priority and age. After Re-read the app shows “The source is being indexed in the background. The status updates on its own.” Through the API you can check the state with GET /api/v1/knowledge/jobs/{id}.
How often does XICBOT retry a failed webhook delivery?
Up to three times in total: the second attempt no earlier than 30 seconds after the first failure, the third no earlier than 2 minutes after the second. If that one fails too, the job has failed. After 20 failed delivery attempts in a row, retries included, XICBOT switches the webhook off.
Can I restart a failed job?
Trigger the work again, for example with Re-read on the source or Sync now in the shop connection. That creates a new job, again with three attempts.
How long do the recipient and content of an email stay in the job?
Until sending is done or has failed for good. XICBOT then cuts the job down to references and deletes it 14 days after it ends. If a send waits longer than 7 days, the job expires.
Why did the knowledge.failed event arrive several times for the same source?
Every failed attempt to read the source triggers it, and a job has up to three attempts.
Ask it yourself, Assistant of this website
Automated assistant