0

I have been trying to use async-lock npm module to lock a /get resource execution.

import cors from "cors";
import express from "express";
import AsyncLock from "async-lock";
import _ from "lodash";

const app = express();
const port = process.env.port || 3001;

app.use(cors());
app.use(express.json());

let synchonizationKey: string = "";
let lock = new AsyncLock();

app.get("/pckg", (req, res) => {
  let id = _.uniqueId();
  console.log("--------------Request ", id, " arrived");

  lock.acquire(
    synchonizationKey,
    function () {
      console.log("--------------Request ", id, " lockAquired");

      setTimeout(function () {
        console.log("--------------Request ", id, " Done");
      }, 3000);
    },
    function (err, ret) {
      console.log("--------------Request ", id, " lockReleased");
      res.send({ id: id });
    },
    {}
  );
});

app.listen(port, () => console.log("Running on port#" + port));

Output: 4 get requests I fired from browser.

--------------Request  1  arrived
--------------Request  1  lockAquired
--------------Request  1  lockReleased
--------------Request  2  arrived
--------------Request  2  lockAquired
--------------Request  2  lockReleased
--------------Request  3  arrived
--------------Request  3  lockAquired
--------------Request  3  lockReleased
--------------Request  4  arrived
--------------Request  4  lockAquired
--------------Request  4  lockReleased
--------------Request  1  Done
--------------Request  2  Done
--------------Request  3  Done
--------------Request  4  Done

I was expecting a result on similar lines as it is answered in this question

It looks like lock is released as soon as all synchronous parts in the callback is executed.

Can someone please help me with this?

Anurag Singh
  • 98
  • 1
  • 6
  • There should be a function called `done`, `next` etc... you need to call it manually in your `setTimeout` code block, if there is any error, generally you need to pass it in that function like: `next(error)`, In this context, What type of problem does `async-lock` solve ? You are making It complex, You don't need any callback library now day... use standard `async/await` instead – Nur Jul 04 '21 at 12:37
  • Client's can call /pckg to run a series of async calls. These async calls needs to be protected across /pckg get requests. – Anurag Singh Jul 04 '21 at 12:46
  • @Nur There are situations where you may need a lock. For instance multiple clients reading and updating the same file, where the second client must not start reading the file, while the other one isn't finished updating. Of course everyone could write such a locking himself using `async/await` but there's no need for everyone reinventing the wheel. Yes nowadays probably a promise-based approach may be preferred -- this is also supported by library. But there is still nothing wrong with using a callback-based approach ... – derpirscher Jul 04 '21 at 13:02

1 Answers1

1

If you look at the docs of the async-lock package, you will notice that the acquire function has the following signature

acquire(
  key,
  executeFunction,
  callbackFunction,
  options);

where the executeFunction itself, has the signature

function(done) {...}

and done is a callback, which is used to call the callbackFunction once the work your critical section is done, and the lock can be released. You are omitting the done parameter and thus, not calling the callbackFunction manually. So it's called (and therefore the lock is released) once the executeFunction is finished. And as the setTimeout in your execution function is of course also async, it won't delay the executionFunction.

So the correct way to use it, is as follows

lock.acquire(
  synchonizationKey,
  function (done) {  // <----- new parameter for the function
    console.log("--------------Request ", id, " lockAquired");

    setTimeout(function () {
      console.log("--------------Request ", id, " Done");
      done();  // <---- call the callback, once the lock can be released 
    }, 3000);
  },
  function (err, ret) {
    console.log("--------------Request ", id, " lockReleased");
    res.send({ id: id });
  },
  {});

This leads to the following output

--------------Request  1  arrived
--------------Request  1  lockAquired
--------------Request  2  arrived
--------------Request  3  arrived
--------------Request  4  arrived
--------------Request  1  Done
--------------Request  1  lockReleased
--------------Request  2  lockAquired
--------------Request  2  Done
--------------Request  2  lockReleased
--------------Request  3  lockAquired
--------------Request  3  Done
--------------Request  3  lockReleased
--------------Request  4  lockAquired
--------------Request  4  Done
--------------Request  4  lockReleased
derpirscher
  • 14,418
  • 3
  • 18
  • 35