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

Race condition with fs.mkdirSync when multiple processes create a client with logging turned on at the same time #141

Open
Lolkekzor opened this issue Jul 17, 2023 · 2 comments

Comments

@Lolkekzor
Copy link

Description

in src/OAuthClient.js#OAuthClient we have the following section of code (https://github.com/intuit/oauth-jsclient/blob/master/src/OAuthClient.js#L61):

if (this.logging) {
  const dir = './logs';
  if (!fs.existsSync(dir)) {
    fs.mkdirSync(dir);
  }
  ...
}

If multiple processes are started on a machine that has no .logs folder created and this section of code is executed, it is feasible that the following timeline happens:

  • Process 1 checks the if condition. No directory exists, so we go into the if block
  • Process 2 checks the if condition. No directory exists, so we go into the if block
  • Process 1 creates directory successfully
  • Process 2 attempts to create a directory but an error is thrown since it already exists

Example error I encountered in a Github CI Actions environment, in a setup where there is a main API process and one worker process for heavy tasks. Both of them encounter the code where they create such a client. The CI run fails for me since the backend is not successfully created due to the error thrown when the worker tries to create a client, in a fashion similar to the one described above. The following error is thrown:

node:internal/fs/utils:347
   throw err;
   ^
Error: EEXIST: file already exists, mkdir './logs'
   at Object.mkdirSync (node:fs:1386:3)
...ommitted more of the message for privacy & brevity
  errno: -17,
  syscall: 'mkdir',
  code: 'EEXIST',
  path: './logs'

To reproduce

Due to the nature of the issue, it can be hard to reproduce, and in the CI environment I ran, it happens rarely, but it does happen.
If multiple processes are started and create the client like

 const client = new OAuthClient({
    clientId: 'id', // Fill these in with actual values
    clientSecret: 'secret',
    environment: 'env',
    redirectUri: 'uri',
    logging: true, // This needs to be true to reproduce the bug
  });

For easier time reproducing this issue, use a bash script that removes the .logs folder and then starts multiple of these processes in parallel

Proposed fix

Not sure what the best practice in this case would be, but something like wrapping the mkdirSync function call and ignoring the EEXIST error code works for me (and is what I do currently in my case to solve the issue for myself), as shown here: https://riptutorial.com/node-js/example/5638/avoiding-race-conditions-when-creating-or-using-an-existing-directory
Not sure if that is hacky or has other downfalls, so am open to a better solution

@rajeshgupta723
Copy link
Collaborator

@caub @Lolkekzor Please feel free to raise a PR for review? Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants