Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
exclusive-lock
Advanced tools
ExclusiveLock
Need to synchronize a bunch of workers so that only 1 does a particular thing? If yes,
then you need a lock file. This package uses a cache store (redis
or keydb
)
to create records atomically that only 1 instance will "own."
This library covers most common use cases for exclusion when working with multiple instances of the same application / container:
For long running tasks and rare edge cases, it could be possible that the lock is perceived as acquired by more than one instance. This library does not provide strict guarantees for exclusion for tasks that must be processed exactly once in a non-idempotent manner (e.g. appending an item in order processing). Consider using upserts/cas on your persistent DB in those cases or using a dedicated solution for exclusion like etcd / zookeeper.
npm install @logdna/exclusive-lock --save
const ExclusiveLock = require('@logdna/exclusive-lock')
const cache_connection = require('./my-keydb-connection.js')
const pino = require('pino')
const exclusive_lock = new ExclusiveLock({
name: 'my-distributed-app'
, log: pino()
, cache_manager
})
async function main() {
const acquired = await exclusive_lock.acquire()
if (acquired) {
log.info('You win the race! Lock acquired')
}
exclusive_lock.release()
}
main()
As a feature, exclusive-lock
will start a timer to automatically refresh the TTL on
the lock file, as it's assumed that the lock holder will always want to hold the lock
until explicitly released. This feature is handled by a setInterval
timer and can
encouter errors asynchronously. See the error
event for details on that.
acquired
.release()
an acquired lock so that the timer is canceled.refreshed
is emitted for every successful refresh.new ExclusiveLock(options)
options
<Object>
name
<String>
- Required A unique string to identify your applicationcache_connection
<Object>
- Required A connection to the cache, either Redis or Keydblog
<Object>
- A optional logger instance such as pino
. Must support levels info
, warn
, error
, debug
. Default: abstract-logginglock_ttl_ms
<Number>
- Optional. Specify a TTL in milliseconds for the lock. Default: 3000lock_refres_ms
<Number>
- Optional. specify a time in milliseconds for refreshing the lock on an interval. Default: 1000lock_contents
<String>
- Optional. Specify the string contents to put in the lock file, e.g. a server/instance name.Throws: <Error>
for validation errors
acquire()
Attempts to exclusively acquire a lock based on the given name
. If multiple
instances are competing, only 1 will win the lock.
Returns: Promise<Boolean>
if the lock was a success
Emits: acquired
inspect()
Returns an object containing the remaining TTL (if any) on the lock, and the serialized lock contents. Useful if lock_contents
was used to store
valuable information in the lock, or to analyze the TTL. Any client can inspect
the lock regardless of who acquired it.
If there is no lock, null
is returned
Returns: Promise<Object<lock_ttl_ms: Number, lock_contents: Object|Number|Boolean|String>>
An object containing the remaining TTL (in milliseconds), plus the contents of the lock
Throws: <Error>
for cache store pipeline
errors
release()
Unlock based on name
. Idempotent. Instances that do not have the lock will
be a no-op.
Returns: Promise<undefined>
Emits: released
'acquired'
key
<String>
- The key value of the lock stored in cacheThis event is emitted after a successful lock is acquired. Because the acquire()
method is async
, there's no real need to listen for this, but it has been added
to remain consistent with the 'released'
event which can happen asynchronously.
'refreshed'
<Object>
- The payload object
This event is emitted after a lock's TTL is successfully refreshed.
'released'
key
<String>
- The key value of the lock stored in cacheThis event is emitted when a lock is released.
'error'
err
<Error>
- A thrown error that occurredThis event is thrown when errors are encountered in the TTL refresh timer. In this case, the error is emitted and the following actions are taken:
release()
will automatically be called. This is so that the lock does
not become expired leaving the lock holder thinking that it's still acquired. Users
should listen for these events and act accordingly.release()
also fails, an 'error'
event will be emitted again with
those details. At that point, the instance will no longer think the lock is acquired, but its record will remain until the TTL expires. This is because the failure in release()
will be because of a failed cache.del()
operation, thus
leaving the key.Copyright © 2022 Mezmo, released under an MIT license. See the LICENSE file and https://opensource.org/licenses/MIT
This project is open-sourced, and accepts PRs from the public for bugs or feature enhancements. These are the guidelines for contributing:
Fixes: #5
FAQs
Create atomic locks that can be used in a distributed environment
The npm package exclusive-lock receives a total of 61 weekly downloads. As such, exclusive-lock popularity was classified as not popular.
We found that exclusive-lock demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.