heroiclabs / nakama

Distributed server for social and realtime games and apps.
https://heroiclabs.com
Apache License 2.0
8.85k stars 1.08k forks source link

multiUpdate() should guarantee atomicity #747

Closed gpiumatti closed 2 years ago

gpiumatti commented 2 years ago

Description

I'm using the JS scripting engine to execute multiUpdate() with the expectation that if any of the update operations fails, the whole transaction will fail. What happens instead is that a part of the update succeeds and another part fails, leaving the user in an intermediate state.

For example: call multiUpdate() with a wallet update (-10 coins) and a storage object update (create new object). If the user wallet has < 10 coins, multiUpdate() throws exception, but the storage object is created.

Steps to Reproduce

function InitModule(ctx, nk, logger, initializer) {
    const newUser = nk.authenticateCustom(nk.uuidv4());
    const userId = newUser.userId;
    const walletUpdates = [
        { userId: userId, changeset: { "coins": -10 }
    ];
    const storageUpdates = [
        { userId: userId, collection: "test", key: "test", value: { testValue: 1 } }
    ];

    nk.multiUpdate(null, walletUpdates, storageUpdates);
}

Expected Result

Actual Result

Context

Run on the server only (not using a client for this test). Using the JS scripting engine.

Your Environment

gpiumatti commented 2 years ago

Interestingly, if multiUpdate() is used the other way around (a wallet update that succeeds and a storage update that fails), then the whole transaction fails and nothing is updated (the user wallet is unchanged)

zyro commented 2 years ago

@gpiumatti Thanks for reporting! I've merged a fix in eb5270fdd5a8ab79f0bed86d51d38a2b6d689a45. This will be part of the next release. 👍

Please re-open this issue if you see further unexpected behaviour after upgrading to the next release.