Skip to content
This repository has been archived by the owner on Feb 12, 2024. It is now read-only.

daemon leaves behind api file lock on error #229

Closed
hackergrrl opened this issue May 17, 2016 · 36 comments · Fixed by ipfs/js-ipfs-repo#123 or #797
Closed

daemon leaves behind api file lock on error #229

hackergrrl opened this issue May 17, 2016 · 36 comments · Fixed by ipfs/js-ipfs-repo#123 or #797
Assignees
Labels
exp/expert Having worked on the specific codebase is important help wanted Seeking public contribution on this issue kind/bug A bug in existing code (including security flaws)

Comments

@hackergrrl
Copy link
Contributor

When the daemon hits an error on load like #228, it will leave around the ~/.ipfs/api file lock.

go-ipfs seems to be smart about detecting this and cleaning it up, but it will inhibit future invocations of the js-ipfs daemon.

@daviddias
Copy link
Member

(@whyrusleeping can confirm) go-ipfs checks if the daemon is indeed on and if it doesn't find anything on the port left behind, it just deletes the lock and spawns the daemon.

@daviddias daviddias added kind/bug A bug in existing code (including security flaws) exp/novice Someone with a little familiarity can pick up help wanted Seeking public contribution on this issue labels May 17, 2016
@hackergrrl
Copy link
Contributor Author

great, so the work is

  • clean up the api lock on daemon error
  • check if the daemon is on on start-up and clear the lock if not

@daviddias
Copy link
Member

exactly :)

@daviddias
Copy link
Member

@noffle would you like to handle this one? :)

@hackergrrl
Copy link
Contributor Author

hackergrrl commented Aug 21, 2016 via email

@daviddias
Copy link
Member

@victorbjelkholm does this look like something you can take on? :) Thank you

@dignifiedquire
Copy link
Member

Just checked the go code, and we are actually not doing what go does at all. In go the api file is deleted on closing, but does not stop the daemon from starting up. Rather it is simply overwritten.

For locking the repo to a single daemon a file called repo.lock is used which uses os level checks to figure out who the file belongs to (https://github.com/ipfs/go-ipfs/blob/master/repo/fsrepo/lock/lock.go)

@dignifiedquire
Copy link
Member

It looks like the best bet for doing this is using

and using those for repo.lock.

@victorb
Copy link
Member

victorb commented Sep 15, 2016

Why can't we not remove the lock file on crash/close? And the only thing the daemon has to check, is if the file is there or not.

@daviddias
Copy link
Member

@victorbjelkholm it gets removed on close, how can you assure that it gets removed on crash?

@dignifiedquire
Copy link
Member

https://github.com/joyent/node-lockfd for unix

Does not work, as it misses the actual important syscall config we need :(

I found https://crates.io/crates/fs2 which is supposed to work on windows as well as on nix systems so I'm looking into creating a small wrapper around it for js.

@victorb
Copy link
Member

victorb commented Sep 15, 2016

@victorbjelkholm it gets removed on close, how can you assure that it gets removed on crash?

@diasdavid by leveraging domain/cluster, which is basically what they are meant for. We can isolate the main process and listen for shutdowns/exists and clean up properly.

@dignifiedquire
Copy link
Member

@diasdavid by leveraging domain/cluster, which is basically what they are meant for. We can isolate the main process and listen for shutdowns/exists and clean up properly.

This does not help at all with things like power loss. Also it's a massive overhead of running two v8 processes just for simple monitoring purposes.

@daviddias
Copy link
Member

@victorbjelkholm also, Domains and Cluster are modules that historically have been a source of issues in Node.js land, so much that they were considered to be removed from core several times. And even with that, it would not save us from problems that are beyond the OS level (machine being shutdown, kernel panic, etc). Checking the API file and testing if the API is running is also how go-ipfs does it //cc @whyrusleeping

@dignifiedquire
Copy link
Member

@diasdavid not entirely see my comment for what actually happens in go: #229 (comment)

@daviddias
Copy link
Member

@dignifiedquire go does:

    1. check for API file
    1. If it exists, tries to dial to that daemon
    1. If there is no daemon running on that port, spawns a new daemon
    1. connects to the new daemon

//cc @whyrusleeping

@dignifiedquire
Copy link
Member

yes but the locking of the repo has nothing to do with the api file. It purely happens through repo.lock as described above

@daviddias
Copy link
Member

ah yes, there are two files, one for the lock, one for the api (where it is listening), the process that owns the API should also own the lock.

@Kubuxu
Copy link
Member

Kubuxu commented Sep 15, 2016

@victorbjelkholm There is a reason why Unix has its own lock function/syscall. If you lock using the dedicated subroutine the lock will be released automatically when process exits, thus preventing stale lock.

Locking by creating file with PID, as done quite frequently, has been proven error full because of PID reuse. It might happen that process crashes, its PID is reused and the lock is considered valid.

repo.lock is repo wide lock, this means that process that wants to provide the API should acquire the lock, and if successful it may consider the whole repo as its own. That is why if go-ipfs acquires lock successfully it doesn't even check if there is api file, it just overwrites it with its own.

@dignifiedquire
Copy link
Member

I finally found a solution to do fcntl based locking for repo.lock that does the exact same thing as go-ipfs so it will integrate cleanly. I hope to have a PR for this up this week.

@daviddias
Copy link
Member

@dignifiedquire this will only work when used with fs store, correct? What is the strategy for all the others?

@dignifiedquire
Copy link
Member

dignifiedquire commented Sep 26, 2016

@diasdavid do we need this anywhere else? This is only related to the http-api/cli as far as I understand

@daviddias
Copy link
Member

That is indeed correct :)

@daviddias daviddias added the status/deferred Conscious decision to pause or backlog label Jan 29, 2017
@dignifiedquire dignifiedquire self-assigned this Mar 14, 2017
@dignifiedquire dignifiedquire added status/in-progress In progress and removed status/deferred Conscious decision to pause or backlog labels Mar 14, 2017
@daviddias daviddias added status/ready Ready to be worked and removed status/in-progress In progress labels Mar 15, 2017
@dignifiedquire dignifiedquire mentioned this issue Mar 19, 2017
4 tasks
@daviddias daviddias removed the status/ready Ready to be worked label Mar 21, 2017
@daviddias
Copy link
Member

As a note, this has been solved :)

@hackergrrl
Copy link
Contributor Author

hackergrrl commented Mar 29, 2017 via email

@KrishnaPG
Copy link
Contributor

While using the js-ipfs in node, encountering this error:

Error: Lock file is already being held
    at options.fs.stat (node_modules\proper-lockfile\lib\lockfile.js:68:47)
    at node_modules\graceful-fs\polyfills.js:285:20
    at FSReqWrap.oncomplete (fs.js:155:5)

During the development, the app is being restarted with code modifications, which leads to the above error frequently. Previous instance holding the lock is fine, but how to override / release it in new instance ?

@timcash
Copy link

timcash commented Jul 27, 2020

Having this problem when trying to integrate with Next.js while in dev mode. Adding the error to help others find

LockExistsError: Lock already being held for file: C:\Users\timca\.jsipfs\repo.lock
    at Object.exports.lock (C:\Users\timca\Documents\GitHub\migo\node_modules\ipfs-repo\src\lock.js:36:13)
    at async IpfsRepo._openLock (C:\Users\timca\Documents\GitHub\migo\node_modules\ipfs-repo\src\index.js:192:22)
    at async IpfsRepo.open (C:\Users\timca\Documents\GitHub\migo\node_modules\ipfs-repo\src\index.js:113:23)
    at async Proxy.init (C:\Users\timca\Documents\GitHub\migo\node_modules\ipfs\src\core\components\init.js:62:9)
    at async Object.create (C:\Users\timca\Documents\GitHub\migo\node_modules\ipfs\src\core\index.js:55:3)
    at async module.exports../pages/api/hello.js.__webpack_exports__.default (C:\Users\timca\Documents\GitHub\migo\.next\server\static\development\pages\api\hello.js:112:12)
    at async apiResolver (C:\Users\timca\Documents\GitHub\migo\node_modules\next\dist\next-server\server\api-utils.js:6:1)
    at async DevServer.handleApiRequest (C:\Users\timca\Documents\GitHub\migo\node_modules\next\dist\next-server\server\next-server.js:43:397)
    at async Object.fn (C:\Users\timca\Documents\GitHub\migo\node_modules\next\dist\next-server\server\next-server.js:35:764)
    at async Router.execute (C:\Users\timca\Documents\GitHub\migo\node_modules\next\dist\next-server\server\router.js:28:28)
    at async DevServer.run (C:\Users\timca\Documents\GitHub\migo\node_modules\next\dist\next-server\server\next-server.js:44:494)     
    at async DevServer.handleRequest (C:\Users\timca\Documents\GitHub\migo\node_modules\next\dist\next-server\server\next-server.js:13:133) {
  code: 'ERR_LOCK_EXISTS'
}

@tinypell3ts
Copy link

I'm also having this problem when using js-ipfs in node:

(node:9746) UnhandledPromiseRejectionWarning: LockExistsError: Lock already being held for file: /Users/admin/.jsipfs/repo.lock

@achingbrain
Copy link
Member

@andykitt this usually happens when another IPFS process is running or the previous process did not exit cleanly - is either of these the case for you?

@runvnc
Copy link

runvnc commented Feb 23, 2022

Has anyone written a wrapper for the IPFS command line that just calls exec or something to get CIDs/add files? I am over this. Can't restart services. Maybe I have to start with a script that just deletes that file/folder every time.

@AlexMesser
Copy link

This worked for me:

const node = await IPFS.create(ipfsConfig)

const stop = () => {
 node.stop()
 process.exit()
}

process.on("SIGTERM", stop)
process.on("SIGINT", stop)
process.on("SIGHUP", stop)
process.on("uncaughtException", stop)

repo.lock successfully deleted on app restart

@achingbrain
Copy link
Member

@AlexMesser node.stop() returns a promise so you'll want to await on its completion before running process.exit() as there's no guarantee it will have finished by the time you exit the process.

@AlexMesser
Copy link

AlexMesser commented Mar 10, 2022

@achingbrain yes, first I tried it with await node.stop() but app didn't terminate when I pressed ctrl + c in terminal. But It works well without await. This discourages me...

UPD: my bad, added try..catch and found an error Lock is already released

const node = await IPFS.create(ipfsConfig)

const stop = async () => {
  try {
    await node.stop()
  } catch (e) {
     console.log(e.message)
  }
 process.exit()
}

process.on("SIGTERM", stop)
process.on("SIGINT", stop)
process.on("SIGHUP", stop)
process.on("uncaughtException", stop)

However it works. Lock file will be deleted anyway.

@HariApplogiq
Copy link

HariApplogiq commented Feb 9, 2023

@achingbrain yes, first I tried it with await node.stop() but app didn't terminate when I pressed ctrl + c in terminal. But It works well without await. This discourages me...

UPD: my bad, added try..catch and found an error Lock is already released

const node = await IPFS.create(ipfsConfig)

const stop = async () => {
  try {
    await node.stop()
  } catch (e) {
     console.log(e.message)
  }
 process.exit()
}

process.on("SIGTERM", stop)
process.on("SIGINT", stop)
process.on("SIGHUP", stop)
process.on("uncaughtException", stop)

However it works. Lock file will be deleted anyway.

this not worked for Still i have LockExistsError: Lock already being held for file
kindly help me resolve this @achingbrain

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
exp/expert Having worked on the specific codebase is important help wanted Seeking public contribution on this issue kind/bug A bug in existing code (including security flaws)
Projects
None yet
Development

Successfully merging a pull request may close this issue.