Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

.release() does not check actual token count #36

Open
cardin opened this issue Sep 5, 2019 · 3 comments
Open

.release() does not check actual token count #36

cardin opened this issue Sep 5, 2019 · 3 comments

Comments

@cardin
Copy link
Contributor

cardin commented Sep 5, 2019

The nr value given to Sema() does not stop .release() from being called as many times as a user wants.

Example below shows an nr value of 1, but the user is able to obtain 2 concurrent uses.

const Sema = require("async-sema").Sema;

let i = 0;
const a = new Sema(1);
a.release();
a.acquire().then(() => {
	i++;
	console.log(`i = ${i}`);
	return a.acquire();
}).then(() => {
	i++;
	console.log(`i = ${i}`);
	return a.acquire();
});
@OlliV
Copy link
Collaborator

OlliV commented Sep 18, 2019

That's sort of by design to avoid the overhead of the if as technically you just shouldn't write such code. Remember that the original intention was to receive and return tokens or instances.

@cardin
Copy link
Contributor Author

cardin commented Sep 19, 2019

The example code was a bit extreme, but it's possible for this to occur accidentally.

If the developer was careless with either of the following, then there'll be more tokens than intended.

  • Pairing: Not one-to-one mapping of .acquire() to .release(), especially due to nested functions or error handling
  • Asynchronity: .acquire() occuring after .release() if async operations were not handled correctly
const sema = new Sema(1);
try {
   // code continues even if .acquire() is waiting or failed
   sema.acquire().then(x => accessDb(sema)).catch(e => {
      console.error(e);
      sema.release(); // unnecessary since finally{} will release it
   });
} finally {
   sema.release();
}
// At this point, there are 2 tokens.
accessDb(sema);

async function accessDb(sema) {
   sema.acquire().then(x => {
      // do something
      sema.release();
   });
}

I do get what you mean though. There's a lot of ways to use the semaphores incorrectly, we can't catch all of it.

But I felt that the semaphore count should at least be consistent, or give warnings if inconsistent. It is a sanity check, if you will. Otherwise it would pretty much go undetected.

@OlliV
Copy link
Collaborator

OlliV commented Sep 19, 2019

Yeah, that makes sense. I'm not against adding a check if it's seen as a useful addition.

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

No branches or pull requests

2 participants