@columenlabs/ lumen- person (中文(简体) )
鲁门的一所商店每人:一个持久对象,其SQLite为他持有每个应用程序的桌子. 每个应用程序都是拥有表格的模块(<module>_*),它的迁移和它的醒悟时间,因此应用程序代码保持相隔,而一个人的数据会加入一个SQL查询,一个备份和一个删除. 没有依赖关系:它运行在工人身上 nodejs_compat (计: AsyncLocalStorage)和任何带有 SQLite 存储的持久对象.
- 资料来源: https://github.com/columenlabs/lumen (中文(简体) ) (单位:千美元)
packages/person麻省理工学院.
安装
bun add @columenlabs/lumen-person
把它固定在与其他卢门软件包相同的准确版本.
商店及其模块
import { DurableObject } from 'cloudflare:workers';
import { PersonObject, type PersonModule, personModule } from '@columenlabs/lumen-person';
const notes: PersonModule<Env> = {
name: 'notes',
migrations: [
'CREATE TABLE notes_items (id INTEGER PRIMARY KEY, title TEXT NOT NULL, at INTEGER NOT NULL)',
],
async call(ctx, method, args) {
if (method === 'add') {
ctx.sql.exec('INSERT INTO notes_items (title, at) VALUES (?, ?)', (args as { title: string }).title, Date.now());
await ctx.wakeAt(Date.now() + 60_000);
return { ok: true };
}
throw new Error(`no ${method}`);
},
async wake(ctx) {
// small steps: stop by ctx.deadline and ask for the next time
},
};
export class PersonStore extends DurableObject<Env> {
private readonly person = new PersonObject(this.ctx, { modules: [notes], extra: this.env });
call(owner: string, module: string, method: string, args?: unknown) {
return this.person.call(owner, module, method, args);
}
alarm() {
return this.person.alarm();
}
}
// In the Worker
const mine = personModule(env.PERSON, email, 'notes');
await mine.call('add', { title: 'Buy saw blades' });
第一个叫人的名字,并声称是商店;一个后来的叫人被拒绝(403).
行预算:没有循环可以花开账户的一天
Cloudflare的自由计划允许一个账户5M持久对象行读取,每天写出100k行,横跨每个对象. 无论是过去还是过去,每个对象中每个 SQL 调用到 UTC 00: 00 为止. 每家店都有定界(budget 在其道具中, RowBudget 内 ./budget 对于任何其他物体:
| 约束 | 默认 | 过吧 |
|---|---|---|
| 一通电话 | 100克行读取,20克写出 | 下个语句; 调用答案 503 |
| 一个醒来 | 200克读取,20克写取 | 同样,对于那个钟声 |
| 商店的UTC日 | 600克读取,12克写取 | 在协调世界时00:00之前拨打503 |
background 每天份额 | 0.6 (中文(简体) ) | 醒来等待第二天(持续到头半小时);电话继续工作 |
数是光标本身的 rowsRead 财务报告和审定财务报表 rowsWritten克劳德弗莱尔的账单. onLimit 每天听到每个关卡一次(警告那里的人). _object.budget 阅读今天的总数和 _object.brake {level: 'background' | 'stop' | 'ok', until?} 从外面设置一个刹车,当整个账户接近其盖子时;在耗尽的一天里,两个都回答。 一个需要不止一个呼叫预算(一个导入,一个重建)的请求,是一小段时间的背景工作,从不一次请求.
规则它保持
- 每个模块的迁移失败. 每个模块在第一个呼叫或唤醒时迁移,每个步骤在一个交易中. 一个步骤,在再次尝试之前,只扔出503的模块回答一分钟;所有其他模块都继续工作. 绝不编辑或重排已发布的步骤:添加一个.
- 每个模块都有一个警报.
_wakes保存每个模块的下一次,商店的警报是最早的. 每个醒了ctx.deadline(30 s) 默认,wakeMs) 顺道过来设定下一次. 一分钟后再试一次 双倍到一小时. - 等待是共享的,工作不是. 当一个电话等待网络(一个接取,一个模型) 其他电话运行。 只有同步工作能维持商店,所以要保持沉重的剖析.
- 电话就位. 代码运行在一个人的商店里, 呼叫同一人通过
personCall运行而不是新请求.
备份、恢复、删除
商店自己的模块 _object (或 personModule(...).own(method) 一个模块:
| 方法 | 对 |
|---|---|
dump | 每个模块存储的表格(封存值仍被封存),每个模块的迁移级别 |
dumpModule {module} | 一个模块的表格 |
loadModule {module, dump, prefix?} | 从垃圾堆替换一个模块的表格。 与 prefix,没有它命名的表格(items装入 <module>_items,所以行移动 从一个更古老的商店 |
load | 从整个垃圾堆替换每个模块的表格 |
wipeModule {module} | 一个模块的表格及其醒悟 |
wipe | 删除整个商店( 每个表格、 密钥和提醒) |
counts | 每个表格行、迁移水平和迁移失败的任何模块 |
从老店里搬入一行
将自己的可持久对象移动到个人商店的应用程序一次一个页面,所以没有步骤将两个商店都拖了很长时间:
- 旧店的答案
exportRows(sql, table, after): 在划线书签后行, 最多500行, 大约4 MB一页( 至少一行, 所以大块仍然移动), 字节为{b64}。 。 。 . - 模块的"醒"每页写入
importRows(sql, table, page)内部ctx.transaction保存书签,要求再次醒来。 行保留了他们的划线符,所以一个页面发送了两次更改什么. - 当每张桌子交叉时,
rowStats两侧(每张表格的行数和最高行数)必须在应用程序从新商店读取之前匹配. 停止旧店的提醒, 并在移动时写作 ; 其数据差异的表格会再次出现 . - 一个老店,把很多人的行放在一个桌子上, 动动每个人的部分:
exportRows(sql, table, after, { where: { sql: 'scope = ?', args: [email] } })财务报告和审定财务报表rowStats(sql, tables, where)使用相同的过滤器.
及时恢复ctx.storage.getBookmarkForTime)恢复了整个商店,每个模块一次. 取而代之,从垃圾堆中恢复一个模块,并将PITR保留给整个商店.
虚拟表格(一个来自 @columenlabs/lumen-ai是因为 findSql)没有被复制:它们的触发器作为行负载填充,然后重建运行.