Skip to content

Lock Context - #1603

Merged
yuce merged 10 commits into
masterfrom
map-lock-context
Jul 24, 2026
Merged

yuce merged 10 commits into
masterfrom
map-lock-context

Conversation

@yuce

@yuce yuce commented Jul 22, 2026 •

Copy link
Copy Markdown
Contributor

This PR implements the LockContext API to fix lock reentrancy issues.
That required me to bump some development time dependencies.

The markdown link checker fails because DDoS protection of hub.docker.com and npmjs.com, please disregard that.

LockContext

AsyncLocalStorage is the only standard mechanism in Node.js that provides the ability to store values in promises and enable access to them. It is used by virtually all of the modern Node.js libraries that need keep context in promise chains (promises that are created in other promises).

In order to solve the data race issue with the Map lock reentrancy behaviour of the Node.js Client, we propose the introduction of the LockContext class to the public API. It autogenerates a lock ID and stores it in an AsyncLocalStorage store. LockContext has a single static member function called run which is named after the corresponding AsyncLocalStorage function. It is defined as follows:

export class LockContext {
    static async run(f: () => Promise<void>) {
        // ...
    }
}

It is used as follows:

const { Client, LockContext } = require('hazelcast-client');
async function task() {
    // each task runs concurrently
    await LockContext.run(async () => {
        await map.lock(key);
        try {
            const value = await map.get(key);
            await map.set(key, value + 1);
        } finally {
            await map.unlock(key);
        }
    });
}

async function main() {
    const client = await Client.newHazelcastClient();
    const key = 'k1';
    const map = await client.getMap('my-map');
    await map.set(key, 0);
    // 100 concurrent tasks
    const tasks = Array.from({length: 100}, task);
    await Promise.all(tasks);
    const value = await map.get(key);
    // v should be 100
    console.log('value:', value);
}

An internal getLockID function is used by Map and MultiMap proxies to retrieve the lock ID and use it as the thread ID in corresponding operations. For all Map and MultiMap methods that use a thread ID, we use it instead of the constant thread ID. No other changes are necessary for the proxy code.

@codecov

codecov Bot commented Jul 22, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (master@3918d65). Learn more about missing BASE report.

Additional details and impacted files
@@            Coverage Diff            @@
##             master    #1603   +/-   ##
=========================================
  Coverage          ?   93.48%           
=========================================
  Files             ?      467           
  Lines             ?    16661           
  Branches          ?     1354           
=========================================
  Hits              ?    15575           
  Misses            ?      792           
  Partials          ?      294           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@yuce
yuce requested a review from emreyigit July 23, 2026 08:53

@emreyigit emreyigit left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm ok with PR, just left a small comment. Rest looks nice to me.

Comment thread src/proxy/LockContext.ts Resolved
@yuce
yuce requested a review from emreyigit July 24, 2026 11:35
@yuce
yuce merged commit 4043745 into master Jul 24, 2026
15 of 16 checks passed
@yuce
yuce deleted the map-lock-context branch July 24, 2026 11:49
@dmitriyrazboev dmitriyrazboev added this to the 5.7.0 milestone Jul 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants