-
-
Notifications
You must be signed in to change notification settings - Fork 56
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
Issues with cross-process concurrency #20
Comments
When I created this I assumed the file system did atomic writes, but clearly not. Seems weird that fs can't handle this for you. |
I spent a little time looking at this today. Unfortunately, it looks like the only way to incorporate a file lock would be to make the entire configstore API asynchronous. Given that this is already a fairly small library, a change like that would essentially amount to a complete rewrite. There's also something to be said for the simplicity of the synchronous interface for use cases that aren't concerned with concurrent access. Do you have any thoughts on what the best path forward on this might be? I'm considering the possibility of just forking/building an asynchronous concurrent-access-safe version of configstore, but wanted to get your insights first. |
I don't see why it would have to be async. Can you elaborate? |
If the lock is already held by another process when we go to read/write the config file, then the two options are either to give up entirely, or to wait some amount of time and check the lock again. In the "just give up" option, clients of the library have to be prepared to handle a "lock already taken" exception potentially being raised by any configstore operation. They then have to implement their own logic to either manually retry after some period of time or otherwise handle the failure. This avoids data corruption, but pushes the problem of actually dealing with concurrent use on to the users of the library. For the "automatically retry" option, we don't want to just hammer the filesystem in a loop checking the lock, so we need to wait some period of time between checks (proper-lockfile does this with nice exponential backoff). The only way I can think of to do this synchronously would be to roll our own file lock implementation that uses fibers or some other native extension to do a synchronous wait. Both the complexity of building a home-grown file lock and introducing the need for native bindings feel like points against that idea. There could definitely be another alternative I'm not seeing, but the only other one I've thought of is an asynchronous interface. |
Another alternative could be to use atomic file writing and just let the last concurrent write win. One concurrent write will overwrite another, but that might not be such a big problem? |
I think having the last concurrent write win is good enough. About the point about the automatically retry, the dummy implementation is to lock the process with a loop: |
I have no idea how to implement "last concurrent write win" behavior :) With node-proper-lockfile it's probably feasible to implement "first concurrent write win", because subsequent calls to lockSync would throw an error.. |
@sheerun We can use atomic file writing: https://github.com/iarna/write-file-atomic It works by writing to a temporary file first, then renaming and overwriting the actual file when done. We would then get "last concurrent write win" for free. |
That's certainly better than corrupted configuration files :) |
@SBoudrias Blocking the process is the point of a synchronous API, but using a busy loop that pegs one CPU core seems less than ideal. @sindresorhus Atomic writes definitely solve the corruption problem, and like you mentioned, it's easy to drop in a package to handle that. If you decide just avoiding total corruption is good enough for this project, then 👍. In casual testing, though, the race condition I hit more often was caused by the read-mutate-write sequences in |
It's connected with sindresorhus/insight#22
Configstore doesn't lock config storage before writing to it. It can result in invalid YAML when instantiating configstore in different processes concurrently.
If configstore encounters invalid YAML, it cleans the store, resulting in sindresorhus/insight#22
The solution is to use file lock around any filesystem call (mkdir, write, read).
The text was updated successfully, but these errors were encountered: