Say you have something like: ```ts async function applyMigrations(storage: DurableObjectStorage) {

Say you have something like:
async function applyMigrations(storage: DurableObjectStorage) {
    await storage.get(...)

    // Do migration stuffs

    await storage.set(...)
}

In DO constructor:
class MyDO extends DurableObject {
    someState!: number

    constructor(ctx: DurableObjectState, env: Env) {
        super(ctx, env)

        console.log('before')
        applyMigrations(ctx.storage).then(() => {
            this.someState = 42
            console.log('initialized')
        })
        console.log('after')
    }
}

There are a few issues with this code:
  • Even if storage.get/storage.set's implementations are sync, because applyMigration is async, .then puts continuation in the next event loop, so the log order will be
    before
    -> after -> initialized. I haven't tested it but unless DO has a different behavior to regular JS, that should be the case.
  • Because continuation goes on the next event loop, the DO is not fully initialized (this.someState is still
    undefined
    ) by the end of current event loop. I don't know if DO is able to process messages in the same event loop as the one doing the construction, but if that's true, then that's an issue.
  • Because initialization is in continuation, if you are using TS then you must null assert `someState!` because as far as TS can see, `this.someState` is not initialized when constructor exits.To fix some of these issues, you have to instead do:```tsclass MyDO extends DurableObject { someState!: number constructor(ctx: DurableObjectState, env: Env) { super(ctx, env) ctx.blockConcurrencyWhile(async () => { await applyMigrations(ctx.storage) this.someState = 42 }) }}```(This however still doesn't fix the last issue and you still have to `someState!`)If a sync KV API is exposed, this entire problem no longer exists.
Was this page helpful?