prevent database access by more than one person

What can I do to prevent more than one player from accessing the database? For example, there is a product and the price of that product is limited. There is only one of that product left and more than one user wants to access this product. How can I prevent this? Is there anything special that Nakama provides for this?

Hey @epelhant we use a technique called Optimistic Concurrency Control with our storage system to optionally prevent concurrent writes to storage objects. You can read more about how to use version strings to guard against concurrent writes here: Heroic Labs Documentation | Collections

There is something like conditional writing for the client side in the document. I want to prevent more than one person from accessing the database on the server side.

Hi, @epelhant.

In this case you may write a custom RPC that calls the Storage functions within Nakama. Make sure you deal with the OCC mentioned by @lugehorsam (if the version sent to the write call is outdated, it will throw an error).

Regards,
Caetano

Can you share an example from the server side regarding OCC? There is not much information about this in Nakama’s documentation.

Also, can it be done in a situation like this? For example, I sell a product and I sell 100 units of that product. If I give a specific message, can I provide person access to the db accordingly?

What is being referenced as OCC is essentially Conditional Writes, as already referenced by @lugehorsam.

Although I think the wallet is likely more suitable for what you’re looking for.

Can you clarify what you mean with:

(…) give a specific message, can I provide person access to the db accordingly
give access to the db"?

You should interact with the db exclusively through the Storage Engine APIs.

I have a code like this in my function on the server side. If there is only one of my items left and more than one user wants to access it, I must prevent this. But I could not find how to show this in the code. Instead of writing an rpc function for this, how can I do these operations in the if in the else statement?

                  if (purchaseData.ProductQuantity == -1) {
                        return new Return().Unexpected(`This product is unlimited ${purchaseData.Id}`)
                    } else {

                        if (purchaseData.ProductQuantity == 1) {

                        }
                    }
var objectId: nkruntime.StorageReadRequest = {
    collection: 'products',
    key: 'product_1',
    userId: nkruntime.SystemUserId, // Assuming this is a public object owned by the system user.
}
var objects: nkruntime.StorageObject[] = [];
try {
    objects = nk.storageRead([ objectId ]);
} catch (error) {
    logger.error('storageRead error: %s', error);
    throw error;
}

if (objects.length !== 1) {
    throw Error('storage object not found');
}

let product = objects[0].value;

if (product.ProductQuantity < 1) {
    throw Error('product unavailable or unlimited');
}

product.ProductQuantity--;

try {
    nk.storageWrite([{
        collection: objectId.collection,
        key: objectId.key,
        userId: objectId.userId,
        version: objects[0].version, // Important to ensure conditional write.
        value: product,
    }]);
} catch (error) {
    // If an update happened concurrently, the write will fail due to the version field.
    logger.error('storageWrite error: %s', error);
    throw error;
}

thank u so much

Thank you very much for your time. There was one last question. More than one user wants to access a certain element in the admin. Here, what effect does writing the version status of the admin user have on other users? So, when I make a conditional write in the admin user, how does this affect other users. In the background? How exactly does the system work? Is there any need for a different process for users who want to access it?

If you mean object updates through the Nakama Console, the version will be applied under the hood so if a write from another user happened between a read and the current “admin” user attempt to write, it will fail.