
CX
29/9/2026
Tóm tắt
blog.share_blog
@cogover/sdk: Project state và lockTrang này thuộc API reference của @cogover/sdk.
State là JSON bền vững, có phạm vi theo workspace, project, namespace và key. State không gắn với một version nên vẫn còn khi publish version project mới.
interface StateEntry<T> {
readonly value: T;
readonly version: number;
readonly expiresAt?: number;
readonly createdAt: number;
readonly updatedAt: number;
}
interface StateWriteOptions {
readonly expectedVersion?: number;
readonly ttlSeconds?: number;
}
interface StateDeleteOptions {
readonly expectedVersion?: number;
}
interface StateNamespace {
readonly name: string;
get<T>(key: string): Promise<StateEntry<T> | null>;
set<T>(key: string, value: T, options?: StateWriteOptions): Promise<StateEntry<T>>;
delete(key: string, options?: StateDeleteOptions): Promise<boolean>;
}
interface ProjectState {
namespace(name: string): StateNamespace;
}const progress = state.namespace("inventory-sync");
const current = await progress.get<{ cursor: string }>("cursor");
const saved = await progress.set("cursor", { cursor: "next-page" }, {
expectedVersion: current?.version ?? 0,
ttlSeconds: 3600,
});
await progress.delete("cursor", { expectedVersion: saved.version });state.namespace(name): StateNamespace
Tạo client immutable cho namespace. Namespace dài tối đa 128 ký tự; key dài tối
đa 255 ký tự. Cả hai phải bắt đầu bằng chữ hoặc số ASCII và chỉ chứa chữ, số,
., _, :, /, -.
namespace.get<T>(key): Promise<StateEntry<T> | null>
Trả null khi không có hoặc đã hết hạn. Entry gồm value, version, createdAt,
updatedAt và expiresAt tuỳ chọn; timestamp là Unix milliseconds.
namespace.set<T>(key, value, options?): Promise<StateEntry<T>>
Ghi một giá trị JSON tối đa 32 KiB: 32.768 byte UTF-8 của dạng JSON.stringify,
trong đó dấu ngoặc kép, dấu gạch chéo ngược hoặc ký tự điều khiển được tính theo
chuỗi escape của nó. ttlSeconds
từ 1 giây đến 365 ngày; bỏ qua để state không tự hết hạn. Hai option phải là safe
integer. expectedVersion áp dụng
compare-and-set: 0 chỉ tạo khi chưa tồn tại, số dương chỉ ghi đúng version, bỏ qua
để upsert vô điều kiện. Xung đột ném StateConflictError; entry trả về chứa version mới.
Mỗi project giữ tối đa 100.000 entry chưa hết hạn: set tạo thêm entry mới khi đã đủ
sẽ ném RateLimitError và không ghi gì, còn cập nhật key đã có vẫn hoạt động bình
thường. Entry hết hạn được tự động xoá và không tính vào giới hạn.
Version đếm số lần ghi kể từ khi entry được tạo. Sau delete hoặc khi hết hạn, lần
set tiếp theo tạo entry mới có version bắt đầu lại từ 1, nên một version đã đọc trước
khi xoá có thể khớp với một entry mới không liên quan (vấn đề ABA). Khi điều này quan
trọng, hãy lưu thêm một token duy nhất của bạn trong value và so sánh cả token đó.
namespace.delete(key, options?): Promise<boolean>
Xoá và trả true nếu entry tồn tại. Có thể dùng expectedVersion như khi set.
State hết hạn được xem như không tồn tại. State API không tạo transaction với Record
API; không dùng để lưu secret, file hoặc dữ liệu lớn.
Lock là lease phân tán theo workspace, project, namespace và key, dùng để ngăn các
execution đồng thời chạy cùng một đoạn xử lý. Cách an toàn mặc định là withLock:
interface LockOptions {
readonly namespace?: string;
readonly waitMs?: number;
readonly leaseMs?: number;
}
interface LockLease {
readonly id: string;
readonly key: string;
readonly namespace: string;
readonly fencingToken: number;
readonly expiresAt: number;
renew(leaseMs?: number): Promise<void>;
release(): Promise<void>;
}
interface DistributedLocks {
acquire(key: string, options?: LockOptions): Promise<LockLease | null>;
withLock<T>(key: string, callback: (lease: LockLease) => T | Promise<T>): Promise<T>;
withLock<T>(key: string, options: LockOptions,
callback: (lease: LockLease) => T | Promise<T>): Promise<T>;
}await locks.withLock("INV-1", { namespace: "invoice", waitMs: 500 }, async lease => {
await processInvoice("INV-1", lease.fencingToken);
// Chỉ cần renew khi công việc có thể tiến gần thời điểm expiresAt.
// await lease.renew(30_000);
});locks.acquire(key, options?): Promise<LockLease | null>
Trả lease hoặc null khi không lấy được trong waitMs. Namespace mặc định là
default; waitMs từ 0 đến 10.000 ms; leaseMs từ 5.000 đến 60.000 ms và mặc
định 30.000 ms. Mỗi invocation giữ tối đa 16 lock; lấy lock thứ 17 ném
ValidationError. Key dài tối đa 255 ký tự, namespace tối đa 128 và dùng cùng quy tắc
ký tự như tên state. Numeric option phải là safe integer.
Thời gian chờ được tính vào wall-clock của lần thực thi. Trong HTTP route, mặc định
có tổng cộng 8 giây (xem Giới hạn của một lần thực thi),
waitMs gần bằng hoặc lớn hơn thời gian còn lại sẽ kết thúc toàn bộ lần thực thi với
response HTTP 422 chung thay vì trả null; hãy giữ waitMs nhỏ hơn nhiều so với thời
gian còn lại.
Lease có id, key, namespace, fencingToken, expiresAt, cùng
renew(leaseMs?) và release(). Cogover renew và release lease theo id trong phạm vi
project đã lấy lock: mọi lần thực thi của cùng project biết id đều có thể renew hoặc
release lease đó, còn project khác thì không. Hãy giữ id riêng tư và không trả nó cho
caller. Lease mất hoặc hết hạn ném LockLostError. release() lặp lại trên cùng object
lease là no-op sau lần thành công.
locks.withLock(key, callback) / locks.withLock(key, options, callback)
Lấy lock, chạy callback rồi release lease. Nếu không lấy được lock, hàm ném
LockUnavailableError. Khi callback ném lỗi, lease được release và lỗi của callback
được ném lại; nếu việc release đó cũng lỗi thì lỗi release bị bỏ qua và lease hết hạn
sau leaseMs. Khi callback thành công nhưng release lỗi, ví dụ LockLostError vì lease
đã hết hạn trong lúc callback chạy, lỗi đó được ném thay cho kết quả của callback. Hàm
không tự renew; callback dài phải gọi lease.renew() trước khi expiresAt.
Lock chỉ bảo đảm một lease hợp lệ tại một thời điểm; timeout, pause hoặc lỗi mạng có
thể làm execution cũ tiếp tục sau khi lease hết hạn. Khi hệ thống đích hỗ trợ,
hãy lưu/kiểm tra fencingToken và từ chối token cũ. Lock không thay thế idempotency,
không tạo exactly-once và không gộp Record API với state thành một transaction.

blog.blogs_related
Bắt đầu đổi mới phương thức vận hành và tự chủ hệ thống quản trị công việc của bạn
CÔNG TY CỔ PHẦN STRINGEE
Văn phòng