osloconcurrency(1)

OSLOCONCURRENCY(1) oslo.concurrency OSLOCONCURRENCY(1)

NAME

osloconcurrency - oslo.concurrency 5.1.1

The oslo concurrency library has utilities for safely running multi-thread, multi-process applications using locking mechanisms and for running external processes.

INSTALLATION

At the command line:

$ pip install oslo.concurrency


Or, if you have virtualenvwrapper installed:

$ mkvirtualenv oslo.concurrency
$ pip install oslo.concurrency


ADMINISTRATOR GUIDE

This section contains information useful to administrators operating a service that uses oslo.concurrency.

Lock File Management

For services that use oslo.concurrency's external lock functionality for interprocess locking, lock files will be stored in the location specified by the lock_path config option in the oslo_concurrency section. These lock files are not automatically deleted by oslo.concurrency because the library has no way to know when the service is done with a lock, and deleting a lock file that is being held by the service would cause concurrency problems. Some services do delete lock files when they are done with them, but deletion of a service's lock files while the service is running should only be done by the service itself. External cleanup methods cannot reasonably know when a lock is no longer needed.

However, to prevent the lock_path directory from growing indefinitely, it is a good idea to occasionally delete all the lock files from it. The only safe time to do this is when the service is not running, such as after a reboot or when the service is down for maintenance. In the latter case, make sure that all related services (such as api, worker, conductor, etc) are down If any process that might hold locks is still running, deleting lock files may introduce inconsistency in the service. One possible approach to this cleanup is to put the lock_path in tmpfs so it will be automatically cleared on reboot.

Note that in general, leftover lock files are a cosmetic nuisance at worst. If you do run into a functional problem as a result of large numbers of lock files, please report it to the Oslo team so we can look into other mitigation strategies.

Frequently Asked Questions

What is the history of the lock file issue?

It comes up every few months when a deployer of OpenStack notices that they have a large number of lock files lying around, apparently unused. A thread is started on the mailing list and one of the Oslo developers has to provide an explanation of why it works the way it does. This FAQ is intended to be an official replacement for the one-off explanation that is usually given.

The code responsible for this behavior has actually moved to the fasteners project, and there is an issue addressing the leftover lock files there. It covers much of the technical history of the problem, as well as some proposed solutions.

Why hasn't this been fixed yet?

Because to the Oslo developers' knowledge, no one has ever had a functional issue as a result of leftover lock files. This makes it a lower priority problem, and because of the complexity of fixing it nobody has been able to yet. If functional issues are found, they should be reported as a bug against oslo.concurrency so they can be tracked. In the meantime, this will likely continue to be treated as a cosmetic annoyance and prioritized appropriately.

Why aren't lock files deleted when the lock is released?

In our testing, when a lock file was deleted while another process was waiting for it, it created a sort of split-brain situation between any process that had been waiting for the deleted file, and any process that attempted to lock the file after it had been deleted. Essentially, two processes could end up holding the same lock at the same time, which made this an unacceptable solution.

Why don't you use some other method of interprocess locking?

We tried. Both Posix and SysV IPC were explored as alternatives. Unfortunately, both have significant issues on Linux. Posix locks cannot be broken if the process holding them crashes (at least not without a reboot). SysV locks have a limited range of numerical ids, and because oslo.concurrency supports string-based lock names, the possibility of collisions when hashing names was too high. It was deemed better to have the file-based locking mechanism that would always work than a different method that introduced serious new problems.

Bonus Question: Why doesn't lock_path default to a temp directory?

Because every process that may need to hold a lock must use the same value for lock_path or it becomes useless. If we allowed lock_path to be unset and just created a temp directory on startup, each process would create its own temp directory and there would be no actual coordination between them.

While this isn't strictly related to the lock file issue, it is another FAQ about oslo.concurrency so it made sense to mention it here.

USAGE

To use oslo.concurrency in a project, import the relevant module. For example:

from oslo_concurrency import lockutils
from oslo_concurrency import processutils


SEE ALSO:

API Documentation



Locking a function (local to a process)

To ensure that a function (which is not thread safe) is only used in a thread safe manner (typically such type of function should be refactored to avoid this problem but if not then the following can help):

@lockutils.synchronized('not_thread_safe')
def not_thread_safe():

pass


Once decorated later callers of this function will be able to call into this method and the contract that two threads will not enter this function at the same time will be upheld. Make sure that the names of the locks used are carefully chosen (typically by namespacing them to your app so that other apps will not chose the same names).

Locking a function (local to a process as well as across process)

To ensure that a function (which is not thread safe or multi-process safe) is only used in a safe manner (typically such type of function should be refactored to avoid this problem but if not then the following can help):

@lockutils.synchronized('not_thread_process_safe', external=True)
def not_thread_process_safe():

pass


Once decorated later callers of this function will be able to call into this method and the contract that two threads (or any two processes) will not enter this function at the same time will be upheld. Make sure that the names of the locks used are carefully chosen (typically by namespacing them to your app so that other apps will not chose the same names).

Enabling fair locking

By default there is no requirement that the lock is fair. That is, it's possible for a thread to block waiting for the lock, then have another thread block waiting for the lock, and when the lock is released by the current owner the second waiter could acquire the lock before the first. In an extreme case you could have a whole string of other threads acquire the lock before the first waiter acquires it, resulting in unpredictable amounts of latency.

For cases where this is a problem, it's possible to specify the use of fair locks:

@lockutils.synchronized('not_thread_process_safe', fair=True)
def not_thread_process_safe():

pass


When using fair locks the lock itself is slightly more expensive (which shouldn't matter in most cases), but it will ensure that all threads that block waiting for the lock will acquire it in the order that they blocked.

The exception to this is when specifying both external and fair locks. In this case, the ordering within a given process will be fair, but the ordering between processes will be determined by the behaviour of the underlying OS.

Common ways to prefix/namespace the synchronized decorator

Since it is highly recommended to prefix (or namespace) the usage of the synchronized there are a few helpers that can make this much easier to achieve.

An example is:

myapp_synchronized = lockutils.synchronized_with_prefix("myapp")


Then further usage of the lockutils.synchronized would instead now use this decorator created above instead of using lockutils.synchronized directly.

Command Line Wrapper

oslo.concurrency includes a command line tool for use in test jobs that need the environment variable OSLO_LOCK_PATH set. To use it, prefix the command to be run with lockutils-wrapper. For example:

$ lockutils-wrapper env | grep OSLO_LOCK_PATH
OSLO_LOCK_PATH=/tmp/tmpbFHK45


CONFIGURATION OPTIONS

oslo.concurrency uses oslo.config to define and manage configuration options to allow the deployer to control how an application uses this library.

oslo_concurrency

disable_process_locking
Type
boolean
Default
False

Enables or disables inter-process locks.

DEPRECATED VARIATIONS

Group Name
DEFAULT disable_process_locking


lock_path
Type
string
Default
<None>

Directory to use for lock files. For security, the specified directory should only be writable by the user running the processes that need locking. Defaults to environment variable OSLO_LOCK_PATH. If external locks are used, a lock path must be set.

DEPRECATED VARIATIONS

Group Name
DEFAULT lock_path


CONTRIBUTOR'S GUIDE

Contributing

If you would like to contribute to the development of oslo's libraries, first you must take a look to this page:

https://specs.openstack.org/openstack/oslo-specs/specs/policy/contributing.html


If you would like to contribute to the development of OpenStack, you must follow the steps in this page:

https://docs.openstack.org/infra/manual/developers.html


Once those steps have been completed, changes to OpenStack should be submitted for review via the Gerrit tool, following the workflow documented at:

https://docs.openstack.org/infra/manual/developers.html#development-workflow


Pull requests submitted through GitHub will be ignored.

Bugs should be filed on Launchpad, not GitHub:

https://bugs.launchpad.net/oslo.concurrency


CHANGES

5.1.1

Fix issues related to tox4

5.1.0

Imported Translations from Zanata

5.0.1

  • Ignore coverage result files
  • Fix fair internal lock used from eventlet.spawn_n
  • Prove that spawn_n with fair lock is broken
  • Cleanup py27 support

5.0.0

  • Log when waiting to acquire lock
  • Imported Translations from Zanata
  • Fix formatting of release list
  • Drop python3.6/3.7 support in testing runtime

4.5.1

  • Remove unnecessary unicode prefixes
  • Fix RequiredOptError when missing lock_path
  • Update CI to use unversioned jobs template
  • Add Python3 yoga unit tests
  • Allow python_exec kwarg to be None
  • Update python testing classifier

4.5.0

Add support for non-blocking locks

4.4.1

  • setup.cfg: Replace dashes with underscores
  • Remove references to 'sys.version_info'
  • Move flake8 as a pre-commit local target
  • Remove lower-constraints remnants

4.4.0

  • Dropping lower constraints testing
  • Use TOX_CONSTRAINTS_FILE
  • Use py3 as the default runtime for tox
  • Monkey patch original current_thread _active in processutils
  • Add Python3 wallaby unit tests
  • Update master for stable/victoria
  • Adding pre-commit

4.3.0

  • Bump bandit version
  • Imported Translations from Zanata

4.2.0

  • Add support for timeout to processutils.execute
  • Update lower-constraints versions

4.1.1

Fix pygments style

4.1.0

  • Stop to use the __future__ module
  • Fix hacking min version to 3.0.1
  • Switch to newer openstackdocstheme and reno versions
  • Remove the unused coding style modules
  • Remove babel.cfg etc
  • Remove six usage
  • Monkey patch original current_thread _active
  • Align contributing doc with oslo's policy
  • Add py38 package metadata
  • Imported Translations from Zanata
  • Bump default tox env from py37 to py38
  • Add release notes links to doc index
  • Add Python3 victoria unit tests
  • Update master for stable/ussuri

4.0.2

  • Use unittest.mock instead of third party mock
  • Update hacking for Python3
  • Don't warn on lock removal if file doesn't exist

4.0.1

  • trivial: Cleanup tox.ini
  • ignore reno builds artifacts
  • remove outdated header
  • Stop to build universal wheel

4.0.0

  • Drop python 2.7 support and testing
  • Stop configuring install_command in tox
  • tox: Trivial cleanup
  • Fix remove_lock test

3.31.0

  • Spiff up docs for *_with_prefix
  • Switch to Ussuri jobs
  • tox: Keeping going with docs
  • Document management and history of lock files
  • Bump the openstackdocstheme extension to 1.20
  • Blacklist sphinx 2.1.0 (autodoc bug)
  • Update the constraints url
  • Update master for stable/train
  • Add lock_with_prefix convenience utility
  • Some test cleanup

3.30.0

  • Add Python 3 Train unit tests
  • Cap Bandit below 1.6.0 and update Sphinx requirement
  • Replace git.openstack.org URLs with opendev.org URLs
  • OpenDev Migration Patch
  • Dropping the py35 testing
  • Follow the new PTI for document build
  • Update master for stable/stein

3.29.1

  • add python 3.7 unit test job
  • Change python3.5 job to python3.7 job on Stein+
  • Update hacking version
  • Stop using setup.py build_sphinx
  • Update mailinglist from dev to discuss

3.29.0

  • Add support for fair locks
  • Clean up .gitignore references to personal tools
  • Don't quote {posargs} in tox.ini
  • Always build universal wheels

3.28.1

  • Imported Translations from Zanata
  • Use templates for cover and lower-constraints
  • ignore warning from bandit for using shell=
  • add lib-forward-testing-python3 test job
  • add python 3.6 unit test job
  • Remove PyPI downloads
  • import zuul job settings from project-config
  • Reorganize that 'Release Notes' in README
  • Update reno for stable/rocky
  • Switch to stestr
  • Add release notes link to README
  • fix tox python3 overrides
  • Remove stale pip-missing-reqs tox test
  • Trivial: Update pypi url to new url

3.27.0

  • set default python to python3
  • Switch pep8 job to python 3
  • fix lower constraints and uncap eventlet
  • add lower-constraints job
  • Updated from global requirements
  • Updated from global requirements

3.26.0

  • Updated from global requirements
  • Updated from global requirements
  • Imported Translations from Zanata
  • Mask passwords only when command execution fails
  • Imported Translations from Zanata
  • Update reno for stable/queens
  • Updated from global requirements
  • Imported Translations from Zanata
  • Updated from global requirements
  • Update doc links in CONTRIBUTING.rst and README.rst
  • Updated from global requirements

3.25.0

  • Add python_exec kwarg to processutils.execute()
  • Updated from global requirements
  • add bandit to pep8 job

3.24.0

  • Remove -U from pip install
  • Avoid tox_install.sh for constraints support
  • Updated from global requirements
  • Remove setting of version/release from releasenotes
  • Updated from global requirements
  • Updated from global requirements
  • Updated from global requirements
  • Imported Translations from Zanata

3.23.0

  • Updated from global requirements
  • Updated from global requirements
  • Updated from global requirements

3.22.0

  • Minor correction to docstrings
  • Updated from global requirements
  • Updated from global requirements
  • Windows: ensure exec calls don't block other greenthreads
  • Update reno for stable/pike
  • Updated from global requirements
  • Add debug log to indicate when external lock is taken

3.21.0

  • Update URLs in documents according to document migration
  • Imported Translations from Zanata
  • Updated from global requirements
  • switch from oslosphinx to openstackdocstheme
  • turn on warning-is-error for sphinx
  • rearrange existing documentation to follow the new layout standard
  • Remove log translations
  • Check reStructuredText documents for common style issues
  • Updated from global requirements
  • Check for SubprocessError by name on Python 3.x

3.20.0

  • Updated from global requirements
  • Using fixtures.MockPatch instead of mockpatch.Patch

3.19.0

  • Updated from global requirements
  • [Fix gate]Update test requirement
  • Updated from global requirements
  • Remove support for py34
  • pbr.version.VersionInfo needs package name (oslo.xyz and not oslo_xyz)
  • Update reno for stable/ocata

3.18.0

  • Automatically convert process_input to bytes
  • Add Constraints support
  • Show team and repo badges on README

3.16.0

  • Updated from global requirements
  • Updated from global requirements
  • Updated from global requirements
  • Imported Translations from Zanata
  • Remove unnecessary requirements
  • [TrivialFix] Replace 'assertTrue(a in b)' with 'assertIn(a, b)'

3.15.0

  • Changed the home-page link
  • Change assertTrue(isinstance()) by optimal assert
  • Enable release notes translation
  • Ignore prlimit argument on Windows
  • Updated from global requirements
  • Updated from global requirements
  • Update reno for stable/newton

3.14.0

  • Updated from global requirements
  • Fix external lock tests on Windows

3.13.0

  • Updated from global requirements
  • Fix parameters of assertEqual are misplaced
  • Add Python 3.5 classifier and venv

3.12.0

  • Updated from global requirements
  • Imported Translations from Zanata
  • Updated from global requirements

3.11.0

Imported Translations from Zanata

3.10.0

  • Imported Translations from Zanata
  • Updated from global requirements
  • Add reno for releasenotes management

3.9.0

  • Add doc/ to pep8 check
  • Remove unused import statement
  • Add timeout option to ssh_execute
  • Fix wrong import example in docstring
  • Trivial: ignore openstack/common in flake8 exclude list

3.8.0

  • Updated from global requirements
  • Imported Translations from Zanata
  • processutils: add support for missing process limits
  • Remove direct dependency on babel
  • Updated from global requirements
  • Updated from global requirements
  • Updated from global requirements
  • Add a few usage examples for lockutils
  • Revert "Use tempfile.tempdir for lock_path if OSLO_LOCK_PATH is not set"
  • Updated from global requirements
  • Use tempfile.tempdir for lock_path if OSLO_LOCK_PATH is not set

3.6.0

Updated from global requirements

3.5.0

  • Updated from global requirements
  • Make ProcessExecutionError picklable
  • Updated from global requirements

3.4.0

  • Update translation setup
  • Add prlimit parameter to execute()
  • Updated from global requirements
  • Updated from global requirements
  • Updated from global requirements
  • Updated from global requirements
  • Imported Translations from Zanata
  • Updated from global requirements

3.3.0

  • Remove unnecessary package in setup.cfg
  • Updated from global requirements
  • Updated from global requirements

3.2.0

  • Updated from global requirements
  • Updated from global requirements
  • Trival: Remove 'MANIFEST.in'
  • Add complementary remove lock with prefix function

3.1.0

Drop python 2.6 support

3.0.0

  • Updated from global requirements
  • Updated from global requirements
  • Remove python 2.6 classifier
  • Remove python 2.6 and cleanup tox.ini
  • Use versionadded and versionchanged in doc
  • Updated from global requirements
  • Imported Translations from Zanata
  • Updated from global requirements

2.8.0

Updated from global requirements

2.7.0

  • Fix Tests to run under OSX
  • Fix coverage configuration and execution
  • Imported Translations from Zanata
  • Move 'history' -> release notes section
  • add auto-generated docs for config options
  • Change ignore-errors to ignore_errors
  • Updated from global requirements
  • Imported Translations from Zanata
  • Use int enumerations for log error constants

2.6.0

  • Removes unused posix-ipc requirement
  • Updated from global requirements
  • Updated from global requirements

2.5.0

  • Updated from global requirements
  • Updated from global requirements
  • Use oslo_utils reflection to get 'f' callable name
  • flake8 - remove unused rules
  • Imported Translations from Transifex
  • Updated from global requirements

2.4.0

  • Imported Translations from Transifex
  • Updated from global requirements
  • Imported Translations from Transifex
  • Updated from global requirements

2.3.0

  • Imported Translations from Transifex
  • Allow preexec_fn method for processutils.execute
  • Updated from global requirements
  • Use pypi name for requirements.txt
  • processutils: ensure on_completion callback is always called
  • Updated from global requirements
  • Remove redundant fileutils
  • Add tox target to find missing requirements

2.2.0

2.1.0

  • Imported Translations from Transifex
  • Updated from global requirements
  • Ensure we 'join' on the timer watchdog thread
  • Use better timing mechanisms instead of time.time()
  • Updated from global requirements
  • Add 2 callbacks to processutils.execute()
  • Updated from global requirements
  • Fix LockFixture docstring
  • Updated from global requirements
  • Switch badges from 'pypip.in' to 'shields.io'
  • Updated from global requirements
  • Replace locks and replace with fasteners library provides ones

2.0.0

Remove oslo namespace package

1.10.0

  • Imported Translations from Transifex
  • Sync from oslo-incubator
  • Updated from global requirements
  • Advertise support for Python3.4 / Remove support for 3.3
  • Updated from global requirements
  • Imported Translations from Transifex
  • Remove run_cross_tests.sh
  • Updated from global requirements
  • Updated from global requirements

1.9.0

  • Add binary parameter to execute and ssh_execute
  • Port processutils to Python 3
  • Uncap library requirements for liberty
  • Move fixtures to test-requirements.txt
  • Fix test_as_root* tests to work when run as root
  • Add pypi download + version badges
  • Standardize setup.cfg summary for oslo libs
  • Imported Translations from Transifex
  • Updated from global requirements
  • Remove tools/run_cross_tests.sh from openstack-common.conf

1.8.0

  • Switch to non-namespaced module imports
  • Remove py33 env from default tox list
  • Add lockutils.get_lock_path() function

1.7.0

  • Imported Translations from Transifex
  • Updated from global requirements

1.6.0

  • Updated from global requirements
  • processutils: execute(): fix option incompatibility

1.5.0

  • Ability to set working directory
  • Add eventlet test check to new tests __init__.py
  • Drop use of namespaced oslo.i18n
  • Updated from global requirements
  • Updated from global requirements
  • Update Oslo imports to remove namespace package

1.4.1

Revert "Port processutils to Python 3"

0.4.0

  • Bump to hacking 0.10
  • Updated from global requirements
  • add watchdog module
  • Updated from global requirements
  • make time format for processutils match lockutils
  • Correct the translation domain for loading messages
  • Add a reader/writer lock
  • Don't use ConfigFilter for lockutils
  • Report import warnings where the import occurs
  • Port processutils to Python 3
  • Activate pep8 check that _ is imported
  • Drop requirements-py3.txt
  • Updated from global requirements
  • Clean up API documentation
  • Workflow documentation is now in infra-manual
  • Remove noqa from test files
  • test compatibility for old imports
  • Fix bug link in README.rst

0.3.0

  • Add external lock fixture
  • Add a TODO for retrying pull request #20
  • Allow the lock delay to be provided
  • Allow for providing a customized semaphore container
  • Move locale files to proper place
  • Flesh out the README
  • Move out of the oslo namespace package
  • Improve testing in py3 environment
  • Only modify autoindex.rst if it exists
  • Imported Translations from Transifex
  • lockutils-wrapper cleanup
  • Don't use variables that aren't initialized

0.2.0

  • Imported Translations from Transifex
  • Use six.wraps
  • Clean up lockutils logging
  • Remove unused incubator modules
  • Improve lock_path help and documentation
  • Add pbr to installation requirements

0.1.0

  • Updated from global requirements
  • Imported Translations from Transifex
  • Updated from global requirements
  • Updated from global requirements
  • Remove extraneous vim editor configuration comments
  • Add deprecated name test case
  • Make lock_wrapper private
  • Support building wheels (PEP-427)
  • Handle Python 3's O_CLOEXEC default
  • Remove hard dep on eventlet
  • Test with both vanilla and eventlet stdlib
  • Imported Translations from Transifex
  • Fix coverage testing
  • Clean up doc header
  • Use ConfigFilter for opts
  • Make lockutils main() a console entry point
  • Expose lockutils opts to config generator
  • Add hacking import exception for i18n
  • Imported Translations from Transifex
  • provide sane cmd exit reporting
  • Imported Translations from Transifex
  • Add lock_path as param to remove_external function
  • Updated from global requirements
  • Cleanup and adding timing to lockutils logging
  • Imported Translations from Transifex
  • Remove oslo-incubator fixture
  • Break up the logging around the lockfile release/unlock
  • Always log the releasing, even under failure
  • Clarify logging in lockutils
  • Imported Translations from Transifex
  • Address race in file locking tests
  • Updated from global requirements
  • Imported Translations from Transifex
  • Updated from global requirements
  • Handle a failure on communicate()
  • Imported Translations from Transifex
  • Add code/api documentation
  • Add history file to documentation
  • Update contributing instructions
  • Work toward Python 3.4 support and testing
  • warn against sorting requirements
  • Log stdout, stderr and command on execute() error
  • Mask passwords in exceptions and error messages
  • Imported Translations from Transifex
  • Address some potential security issues in lockutils
  • Use file locks by default again
  • Switch to oslo.i18n in our code
  • Imported Translations from Transifex
  • Switch to oslo.utils in our code
  • Mask passwords in exceptions and error messages
  • Initial translation setup
  • Fix docs generation
  • Make all tests pass
  • exported from oslo-incubator by graduate.sh
  • Remove oslo.log from lockutils
  • lockutils: split tests and run in Python 3
  • Fix exception message in openstack.common.processutils.execute
  • Allow test_lockutils to run in isolation
  • Remove `processutils` dependency on `log`
  • Don't import fcntl on Windows
  • Fix broken formatting of processutils.execute log statement
  • Move nova.utils.cpu_count() to processutils module
  • pep8: fixed multiple violations
  • fixed typos found by RETF rules
  • Mask passwords that are included in commands
  • Improve help strings
  • Remove str() from LOG.* and exceptions
  • Fixed several typos
  • Emit a log statement when releasing internal lock
  • Allow passing environment variables to execute()
  • Use oslotest instead of common test module
  • Remove rendundant parentheses of cfg help strings
  • Allow external locks to work with threads
  • Re-enable file-based locking behavior
  • Use Posix IPC in lockutils
  • Update log translation domains
  • Update oslo log messages with translation domains
  • Move the released file lock to the successful path
  • Add remove external lock files API in lockutils
  • Catch OSError in processutils
  • Use threading.ThreadError instead of reraising IOError
  • Have the interprocess lock follow lock conventions
  • lockutils: move directory creation in lock class
  • lockutils: remove lock_path parameter
  • lockutils: expand add_prefix
  • lockutils: remove local usage
  • lockutils: do not grab the lock in creators
  • Remove unused variables
  • Utilizes assertIsNone and assertIsNotNone
  • Fix i18n problem in processutils module
  • lockutils: split code handling internal/external lock
  • lockutils: fix testcase wrt Semaphore
  • Use hacking import_exceptions for gettextutils._
  • Correct invalid docstrings
  • Fix violations of H302:import only modules
  • Fixed misspellings of common words
  • Trivial: Make vertical white space after license header consistent
  • Unify different names between Python2/3 with six.moves
  • Remove vim header
  • Use six.text_type instead of unicode function in tests
  • Adjust import order according to PEP8 imports rule
  • fix lockutils.lock() to make it thread-safe
  • Add main() to lockutils that creates temp dir for locks
  • Allow lockutils to get lock_path conf from envvar
  • Correct execute() to check 0 in check_exit_code
  • Replace assertEquals with assertEqual
  • Move LockFixture into a fixtures module
  • Fix to properly log when we release a semaphore
  • Add LockFixture to lockutils
  • Modify lockutils.py due to dispose of eventlet
  • Replace using tests.utils part2
  • Fix processutils.execute errors on windows
  • Bump hacking to 0.7.0
  • Replace using tests.utils with openstack.common.test
  • Allow passing a logging level to processutils.execute
  • BaseException.message is deprecated since Python 2.6
  • Fix locking bug
  • Move synchronized body to a first-class function
  • Make lock_file_prefix optional
  • Enable H302 hacking check
  • Enable hacking H404 test
  • Use param keyword for docstrings
  • Use Python 3.x compatible octal literal notation
  • Use Python 3.x compatible except construct
  • Enable hacking H402 test
  • python3: python3 binary/text data compatbility
  • Removes len() on empty sequence evaluation
  • Added convenience APIs for lockutils
  • Import trycmd and ssh_execute from nova
  • Update processutils
  • Use print_function __future__ import
  • Improve Python 3.x compatibility
  • Replaces standard logging with common logging
  • Locking edge case when lock_path does not exist
  • lockutils: add a failing unit test
  • lockutils: improve the external locks test
  • Removes unused imports in the tests module
  • Fix locking issues in Windows
  • Fix Copyright Headers - Rename LLC to Foundation
  • Use oslo-config-2013.1b3
  • Emit a warning if RPC calls made with lock
  • Default lockutils to using a tempdir
  • Replace direct use of testtools BaseTestCase
  • Use testtools as test base class
  • Start adding reusable test fixtures
  • Fixes import order errors
  • Log when release file lock
  • Eliminate sleep in the lockutils test case (across processes)
  • Disable lockutils test_synchronized_externally
  • Fix import order in openstack/common/lockutils.py
  • Make project pyflakes clean
  • updating sphinx documentation
  • Remove unused greenthread import in lockutils
  • Move utils.execute to its own module
  • Fix missing import in lockutils
  • Move nova's util.synchronized decorator to openstack common

API REFERENCE

oslo_concurrency.fixture.lockutils

class oslo_concurrency.fixture.lockutils.ExternalLockFixture
Bases: fixtures.fixture.Fixture

Configure lock_path so external locks can be used in unit tests.

Creates a temporary directory to hold file locks and sets the oslo.config lock_path opt to use it. This can be used to enable external locking on a per-test basis, rather than globally with the OSLO_LOCK_PATH environment variable.

Example:

def test_method(self):

self.useFixture(ExternalLockFixture())
something_that_needs_external_locks()


Alternatively, the useFixture call could be placed in a test class's setUp method to provide this functionality to all tests in the class.

New in version 0.3.

setUp()
Prepare the Fixture for use.

This should not be overridden. Concrete fixtures should implement _setUp. Overriding of setUp is still supported, just not recommended.

After setUp has completed, the fixture will have one or more attributes which can be used (these depend totally on the concrete subclass).

Raises
MultipleExceptions if _setUp fails. The last exception captured within the MultipleExceptions will be a SetupError exception.
Returns
None.
Changed in 1.3
The recommendation to override setUp has been reversed - before 1.3, setUp() should be overridden, now it should not be.
Changed in 1.3.1
BaseException is now caught, and only subclasses of Exception are wrapped in MultipleExceptions.



class oslo_concurrency.fixture.lockutils.LockFixture(name, lock_file_prefix=None)
Bases: fixtures.fixture.Fixture

External locking fixture.

This fixture is basically an alternative to the synchronized decorator with the external flag so that tearDowns and addCleanups will be included in the lock context for locking between tests. The fixture is recommended to be the first line in a test method, like so:

def test_method(self):

self.useFixture(LockFixture('lock_name'))
...


or the first line in setUp if all the test methods in the class are required to be serialized. Something like:

class TestCase(testtools.testcase):

def setUp(self):
self.useFixture(LockFixture('lock_name'))
super(TestCase, self).setUp()
...


This is because addCleanups are put on a LIFO queue that gets run after the test method exits. (either by completing or raising an exception)

setUp()
Prepare the Fixture for use.

This should not be overridden. Concrete fixtures should implement _setUp. Overriding of setUp is still supported, just not recommended.

After setUp has completed, the fixture will have one or more attributes which can be used (these depend totally on the concrete subclass).

Raises
MultipleExceptions if _setUp fails. The last exception captured within the MultipleExceptions will be a SetupError exception.
Returns
None.
Changed in 1.3
The recommendation to override setUp has been reversed - before 1.3, setUp() should be overridden, now it should not be.
Changed in 1.3.1
BaseException is now caught, and only subclasses of Exception are wrapped in MultipleExceptions.



oslo_concurrency.lockutils

exception oslo_concurrency.lockutils.AcquireLockFailedException(lock_name)
Bases: Exception

class oslo_concurrency.lockutils.FairLocks
Bases: object

A garbage collected container of fair locks.

With a fair lock, contending lockers will get the lock in the order in which they tried to acquire it.

This collection internally uses a weak value dictionary so that when a lock is no longer in use (by any threads) it will automatically be removed from this container by the garbage collector.

get(name)
Gets (or creates) a lock with a given name.
Parameters
name -- The lock name to get/create (used to associate previously created names with the same lock).

Returns an newly constructed lock (or an existing one if it was already created for the given name).



class oslo_concurrency.lockutils.ReaderWriterLock(*args, **kwargs)
Bases: fasteners.lock.ReaderWriterLock

A reader/writer lock.

New in version 0.4.


class oslo_concurrency.lockutils.Semaphores
Bases: object

A garbage collected container of semaphores.

This collection internally uses a weak value dictionary so that when a semaphore is no longer in use (by any threads) it will automatically be removed from this container by the garbage collector.

New in version 0.3.

get(name)
Gets (or creates) a semaphore with a given name.
Parameters
name -- The semaphore name to get/create (used to associate previously created names with the same semaphore).

Returns an newly constructed semaphore (or an existing one if it was already created for the given name).



oslo_concurrency.lockutils.external_lock(name, lock_file_prefix=None, lock_path=None)

oslo_concurrency.lockutils.get_lock_path(conf)
Return the path used for external file-based locks.
Parameters
conf (oslo_config.cfg.ConfigOpts) -- Configuration object

New in version 1.8.


oslo_concurrency.lockutils.internal_fair_lock(name)

oslo_concurrency.lockutils.internal_lock(name, semaphores=None, blocking=True)

oslo_concurrency.lockutils.lock(name, lock_file_prefix=None, external=False, lock_path=None, do_log=True, semaphores=None, delay=0.01, fair=False, blocking=True)
Context based lock

This function yields a threading.Semaphore instance (if we don't use eventlet.monkey_patch(), else semaphore.Semaphore) unless external is True, in which case, it'll yield an InterProcessLock instance.

Parameters
  • lock_file_prefix -- The lock_file_prefix argument is used to provide lock files on disk with a meaningful prefix.
  • external -- The external keyword argument denotes whether this lock should work across multiple processes. This means that if two different workers both run a method decorated with @synchronized('mylock', external=True), only one of them will execute at a time.
  • lock_path -- The path in which to store external lock files. For external locking to work properly, this must be the same for all references to the lock.
  • do_log -- Whether to log acquire/release messages. This is primarily intended to reduce log message duplication when lock is used from the synchronized decorator.
  • semaphores -- Container that provides semaphores to use when locking. This ensures that threads inside the same application can not collide, due to the fact that external process locks are unaware of a processes active threads.
  • delay -- Delay between acquisition attempts (in seconds).
  • fair -- Whether or not we want a "fair" lock where contending lockers will get the lock in the order in which they tried to acquire it.
  • blocking -- Whether to wait forever to try to acquire the lock. Incompatible with fair locks because those provided by the fasteners module doesn't implements a non-blocking behavior.


Changed in version 0.2: Added do_log optional parameter.

Changed in version 0.3: Added delay and semaphores optional parameters.


oslo_concurrency.lockutils.lock_with_prefix(lock_file_prefix)
Partial object generator for the lock context manager.

Redefine lock in each project like so:

(in nova/utils.py)
from oslo_concurrency import lockutils
_prefix = 'nova'
lock = lockutils.lock_with_prefix(_prefix)
lock_cleanup = lockutils.remove_external_lock_file_with_prefix(_prefix)
(in nova/foo.py)
from nova import utils
with utils.lock('mylock'):

...


Eventually clean up with:

lock_cleanup('mylock')


Parameters
lock_file_prefix -- A string used to provide lock files on disk with a meaningful prefix. Will be separated from the lock name with a hyphen, which may optionally be included in the lock_file_prefix (e.g. 'nova' and 'nova-' are equivalent).


oslo_concurrency.lockutils.main()

oslo_concurrency.lockutils.remove_external_lock_file(name, lock_file_prefix=None, lock_path=None, semaphores=None)
Remove an external lock file when it's not used anymore This will be helpful when we have a lot of lock files

oslo_concurrency.lockutils.remove_external_lock_file_with_prefix(lock_file_prefix)
Partial object generator for the remove lock file function.

Redefine remove_external_lock_file_with_prefix in each project like so:

(in nova/utils.py)
from oslo_concurrency import lockutils
_prefix = 'nova'
synchronized = lockutils.synchronized_with_prefix(_prefix)
lock = lockutils.lock_with_prefix(_prefix)
lock_cleanup = lockutils.remove_external_lock_file_with_prefix(_prefix)
(in nova/foo.py)
from nova import utils
@utils.synchronized('mylock')
def bar(self, *args):

... def baz(self, *args):
...
with utils.lock('mylock'):
...
... <eventually call lock_cleanup('mylock') to clean up>


The lock_file_prefix argument is used to provide lock files on disk with a meaningful prefix.


oslo_concurrency.lockutils.set_defaults(lock_path)
Set value for lock_path.

This can be used by tests to set lock_path to a temporary directory.


oslo_concurrency.lockutils.synchronized(name, lock_file_prefix=None, external=False, lock_path=None, semaphores=None, delay=0.01, fair=False, blocking=True)
Synchronization decorator.

Decorating a method like so:

@synchronized('mylock')
def foo(self, *args):

...


ensures that only one thread will execute the foo method at a time.

Different methods can share the same lock:

@synchronized('mylock')
def foo(self, *args):

... @synchronized('mylock') def bar(self, *args):
...


This way only one of either foo or bar can be executing at a time.

Changed in version 0.3: Added delay and semaphores optional parameter.


oslo_concurrency.lockutils.synchronized_with_prefix(lock_file_prefix)
Partial object generator for the synchronization decorator.

Redefine @synchronized in each project like so:

(in nova/utils.py)
from oslo_concurrency import lockutils
_prefix = 'nova'
synchronized = lockutils.synchronized_with_prefix(_prefix)
lock_cleanup = lockutils.remove_external_lock_file_with_prefix(_prefix)
(in nova/foo.py)
from nova import utils
@utils.synchronized('mylock')
def bar(self, *args):

...


Eventually clean up with:

lock_cleanup('mylock')


Parameters
lock_file_prefix -- A string used to provide lock files on disk with a meaningful prefix. Will be separated from the lock name with a hyphen, which may optionally be included in the lock_file_prefix (e.g. 'nova' and 'nova-' are equivalent).


oslo_concurrency.opts

oslo_concurrency.opts.list_opts()
Return a list of oslo.config options available in the library.

The returned list includes all oslo.config options which may be registered at runtime by the library.

Each element of the list is a tuple. The first element is the name of the group under which the list of elements in the second element will be registered. A group name of None corresponds to the [DEFAULT] group in config files.

This function is also discoverable via the 'oslo_concurrency' entry point under the 'oslo.config.opts' namespace.

The purpose of this is to allow tools like the Oslo sample config file generator to discover the options exposed to users by this library.

Returns
a list of (group_name, opts) tuples


oslo_concurrency.processutils

System-level utilities and helper functions.

exception oslo_concurrency.processutils.InvalidArgumentError(message=None)
Bases: Exception

class oslo_concurrency.processutils.LogErrors(value)
Bases: enum.IntEnum

Enumerations that affect if stdout and stderr are logged on error.

New in version 2.7.

ALL = 1
Log an error on each occurence of an error.

DEFAULT = 0
No logging on errors.

FINAL = 2
Log an error on the last attempt that errored only.


exception oslo_concurrency.processutils.NoRootWrapSpecified(message=None)
Bases: Exception

exception oslo_concurrency.processutils.ProcessExecutionError(stdout=None, stderr=None, exit_code=None, cmd=None, description=None)
Bases: Exception

class oslo_concurrency.processutils.ProcessLimits(**kw)
Bases: object

Resource limits on a process.

Attributes:

  • address_space: Address space limit in bytes
  • core_file_size: Core file size limit in bytes
  • cpu_time: CPU time limit in seconds
  • data_size: Data size limit in bytes
  • file_size: File size limit in bytes
  • memory_locked: Locked memory limit in bytes
  • number_files: Maximum number of open files
  • number_processes: Maximum number of processes
  • resident_set_size: Maximum Resident Set Size (RSS) in bytes
  • stack_size: Stack size limit in bytes

This object can be used for the prlimit parameter of execute().

prlimit_args()
Create a list of arguments for the prlimit command line.


exception oslo_concurrency.processutils.UnknownArgumentError(message=None)
Bases: Exception

oslo_concurrency.processutils.execute(*cmd, **kwargs)
Helper method to shell out and execute a command through subprocess.

Allows optional retry.

Parameters
  • cmd (string) -- Passed to subprocess.Popen.
  • cwd (string) -- Set the current working directory
  • process_input (string or bytes) -- Send to opened process.
  • env_variables (dict) -- Environment variables and their values that will be set for the process.
  • check_exit_code (boolean, int, or [int]) -- Single bool, int, or list of allowed exit codes. Defaults to [0]. Raise ProcessExecutionError unless program exits with one of these code.
  • delay_on_retry (boolean) -- True | False. Defaults to True. If set to True, wait a short amount of time before retrying.
  • attempts (int) -- How many times to retry cmd.
  • run_as_root (boolean) -- True | False. Defaults to False. If set to True, the command is prefixed by the command specified in the root_helper kwarg.
  • root_helper (string) -- command to prefix to commands called with run_as_root=True
  • shell (boolean) -- whether or not there should be a shell used to execute this command. Defaults to false.
  • loglevel (int. (Should be logging.DEBUG or logging.INFO)) -- log level for execute commands.
  • log_errors (LogErrors) -- Should stdout and stderr be logged on error? Possible values are DEFAULT, FINAL, or ALL. Note that the values FINAL and ALL are only relevant when multiple attempts of command execution are requested using the attempts parameter.
  • binary (boolean) -- On Python 3, return stdout and stderr as bytes if binary is True, as Unicode otherwise.
  • on_execute (function(subprocess.Popen)) -- This function will be called upon process creation with the object as a argument. The Purpose of this is to allow the caller of processutils.execute to track process creation asynchronously.
  • on_completion (function(subprocess.Popen)) -- This function will be called upon process completion with the object as a argument. The Purpose of this is to allow the caller of processutils.execute to track process completion asynchronously.
  • preexec_fn (function()) -- This function will be called in the child process just before the child is executed. WARNING: On windows, we silently drop this preexec_fn as it is not supported by subprocess.Popen on windows (throws a ValueError)
  • prlimit (ProcessLimits) -- Set resource limits on the child process. See below for a detailed description.
  • python_exec (string) -- The python executable to use for enforcing prlimits. If this is not set or is None, it will default to use sys.executable.
  • timeout (int) -- Timeout (in seconds) to wait for the process termination. If timeout is reached, subprocess.TimeoutExpired is raised.

Returns
(stdout, stderr) from process execution
Raises
UnknownArgumentError on receiving unknown arguments
Raises
ProcessExecutionError
Raises
OSError
Raises
subprocess.TimeoutExpired

The prlimit parameter can be used to set resource limits on the child process. If this parameter is used, the child process will be spawned by a wrapper process which will set limits before spawning the command.

Changed in version 3.17: process_input can now be either bytes or string on python3.

Changed in version 3.4: Added prlimit optional parameter.

Changed in version 1.5: Added cwd optional parameter.

Changed in version 1.9: Added binary optional parameter. On Python 3, stdout and stderr are now returned as Unicode strings by default, or bytes if binary is true.

Changed in version 2.1: Added on_execute and on_completion optional parameters.

Changed in version 2.3: Added preexec_fn optional parameter.


oslo_concurrency.processutils.get_worker_count()
Utility to get the default worker count.
Returns
The number of CPUs if that can be determined, else a default worker count of 1 is returned.


oslo_concurrency.processutils.ssh_execute(ssh, cmd, process_input=None, addl_env=None, check_exit_code=True, binary=False, timeout=None, sanitize_stdout=True)
Run a command through SSH.
Parameters
  • ssh -- An SSH Connection object.
  • cmd -- The command string to run.
  • check_exit_code -- If an exception should be raised for non-zero exit.
  • timeout -- Max time in secs to wait for command execution.
  • sanitize_stdout -- Defaults to True. If set to True, stdout is sanitized i.e. any sensitive information like password in command output will be masked.

Returns
(stdout, stderr) from command execution through SSH.

Changed in version 1.9: Added binary optional parameter.


oslo_concurrency.processutils.trycmd(*args, **kwargs)
A wrapper around execute() to more easily handle warnings and errors.

Returns an (out, err) tuple of strings containing the output of the command's stdout and stderr. If 'err' is not empty then the command can be considered to have failed.

Parameters
discard_warnings (boolean) -- True | False. Defaults to False. If set to True, then for succeeding commands, stderr is cleared
Returns
(out, err) from process execution


oslo_concurrency.watchdog

Watchdog module.

New in version 0.4.

oslo_concurrency.watchdog.watch(logger, action, level=10, after=5.0)
Log a message if an operation exceeds a time threshold.

This context manager is expected to be used when you are going to do an operation in code which might either deadlock or take an extraordinary amount of time, and you'd like to emit a status message back to the user that the operation is still ongoing but has not completed in an expected amount of time. This is more user friendly than logging 'start' and 'end' events and making users correlate the events to figure out they ended up in a deadlock.

Parameters
  • logger -- an object that complies to the logger definition (has a .log method).
  • action -- a meaningful string that describes the thing you are about to do.
  • level -- the logging level the message should be emitted at. Defaults to logging.DEBUG.
  • after -- the duration in seconds before the message is emitted. Defaults to 5.0 seconds.


Example usage:

FORMAT = '%(asctime)-15s %(message)s'
logging.basicConfig(format=FORMAT)
LOG = logging.getLogger('mylogger')
with watchdog.watch(LOG, "subprocess call", logging.ERROR):

subprocess.call("sleep 10", shell=True)
print "done"



oslo.concurrency-5.1.1

RELEASE NOTES

Read also the oslo.concurrency Release Notes.

INDICES AND TABLES

  • genindex
  • modindex
  • search

AUTHOR

unknown

COPYRIGHT

2023, OpenStack Foundation

October 26, 2023 5.1.1