Retain operations in an offline queue
Keep an order visible while delivery waits for connectivity.
Create failed order enqueues one order and runs two 503 sync attempts with maxRetries: 1 and a 10 ms linear backoff. Retry first failed order calls retryOne(id), Retry all failed orders calls retryAll(), and Discard failed orders calls discardFailed(). The mounted view refreshes pending, failed, syncing, failed IDs and the last action.
Table of contents
Main APIs
- OfflineQueue
- Stores operations, processes them when the network is available and exposes pending and failed counts plus syncing state.
tsimport { mount, onRemove, update, v } from "valyrian.js";
import { OfflineQueue } from "valyrian.js/offline";
import { NetworkManager } from "valyrian.js/network";
const exampleState = {
nextOrder: 1,
rejectDelivery: true,
lastAction: "Ready",
};
const network = new NetworkManager();
const queue = new OfflineQueue({
id: "orders",
network,
maxRetries: 1,
backoff: { strategy: "linear", baseMs: 10, maxMs: 10 },
handler: async (operation) => {
const response = exampleState.rejectDelivery
? new Response(JSON.stringify({ message: "Delivery unavailable" }), {
status: 503,
statusText: "Service Unavailable",
headers: { "Content-Type": "application/json" },
})
: new Response(null, { status: 204 });
if (response.ok === false) {
throw new Error(`Order delivery failed (${response.status})`);
}
exampleState.lastAction = `Delivered ${operation.id}`;
},
});
const stop = queue.on("change", () => update());
async function createFailedOrder() {
exampleState.rejectDelivery = true;
queue.enqueue({
type: "create-order",
payload: { sku: `A-${exampleState.nextOrder}` },
});
exampleState.nextOrder += 1;
await queue.sync();
await queue.sync();
exampleState.lastAction = "Created one failed order";
update();
}
async function retryOneFailed() {
const operation = queue.failed()[0];
if (!operation) {
exampleState.lastAction = "No failed order to retry";
update();
return;
}
exampleState.rejectDelivery = false;
queue.retryOne(operation.id);
await queue.sync();
exampleState.lastAction = `Retried ${operation.id}`;
update();
}
async function retryAllFailed() {
exampleState.rejectDelivery = false;
queue.retryAll();
await queue.sync();
exampleState.lastAction = "Retried all failed orders";
update();
}
function discardAllFailed() {
queue.discardFailed();
exampleState.lastAction = "Discarded all failed orders";
update();
}
function QueueStatus() {
onRemove(() => {
stop();
queue.destroy();
network.destroy();
});
const state = queue.state();
const summary = `Pending: ${state.pending}; failed: ${state.failed}; syncing: ${state.syncing}`;
if (typeof v !== "function") {
return summary;
}
const failedIds =
queue
.failed()
.map((operation) => operation.id)
.join(", ") || "none";
return v(
"main",
{},
v("p", {}, summary),
v("p", {}, `Failed IDs: ${failedIds}`),
v("p", {}, exampleState.lastAction),
v("button", { onclick: createFailedOrder }, "Create failed order"),
v("button", { onclick: retryOneFailed }, "Retry first failed order"),
v("button", { onclick: retryAllFailed }, "Retry all failed orders"),
v("button", { onclick: discardAllFailed }, "Discard failed orders"),
);
}
mount("body", QueueStatus);Error
Failed operations increase the failed count and remain available to `retryOne`, `retryAll` or `discardFailed`.