Skip to content

Commit

Permalink
Added empire.Broodlord preset
Browse files Browse the repository at this point in the history
  • Loading branch information
idlesign committed Oct 13, 2017
1 parent d2eb7b2 commit 36fb796
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 31 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ uwsgiconf changelog
===================


Unreleased
----------
+ Added empire.Broodlord preset


v0.11.0
-------
+ Added support for multiple configurations in one module.
Expand Down
5 changes: 5 additions & 0 deletions docs/source/index_presets.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
Presets
=======

Presets are means to reduce boilerplate code.

Use them as shortcuts to spend less time on configuring.

.. toctree::
:maxdepth: 3

preset_empire
preset_nice
53 changes: 25 additions & 28 deletions docs/source/quickstart.rst
Original file line number Diff line number Diff line change
Expand Up @@ -85,44 +85,41 @@ Now we are ready to use this configuration:
Configuration with multiple sections
------------------------------------

Let's configure uWSGI to use Emperor Broodlord mode as described here_.
Let's configure uWSGI to use Emperor Broodlord mode as described here_ using ``Broodlord`` preset.

.. _here: http://uwsgi-docs.readthedocs.io/en/latest/Broodlord.html#a-simple-example


.. code-block:: python
from uwsgiconf.config import Configuration, Section
from uwsgiconf.config import Section, Configuration
from uwsgiconf.presets.empire import Broodlord
emperor, zerg = Broodlord(
BROODLORD_SOCKET = '/tmp/broodlord.sock'
zerg_socket='/tmp/broodlord.sock',
zerg_count=40,
zerg_die_on_idle=30,
# We'll use the same basic params both for Broodlord Emperor and his zergs.
base_section = (
Section().
master_process.set_basic_params(enable=True).
workers.set_basic_params(count=1).
logging.set_basic_params(no_requests=True).
python.set_wsgi_params(module='werkzeug.testapp:test_app'))
# NOTE. There is a shortcut for ``set_basic_params`` methods:
# Instead of `master_process.set_basic_params(enable=True)`
# you can say plain `master_process(enable=True)`, yet
# in than case you won't get any arg hints from you IDE.
vassals_home='/etc/vassals',
vassal_backlog_items_sos=10,
# Now we add two sections based on common parameters into our configuration:
configuration = Configuration([
# We'll use the same basic params both for Broodlord Emperor and his zergs.
section_emperor=(Section().
# NOTE. Here we use a shortcut for ``set_basic_params`` methods:
# E.g.: instead of `master_process.set_basic_params(enable=True)`
# you say `master_process(enable=True)`.
# But in that case you won't get any arg hints from you IDE.
master_process(enable=True).
workers(count=1).
logging(no_requests=True).
python.set_wsgi_params(module='werkzeug.testapp:test_app')
),
# This section is for Broodlord Emperor.
Section.derive_from(base_section).
networking.register_socket(Section.networking.sockets.default(':3031')).
workers.set_zerg_server_params(socket=BROODLORD_SOCKET).
empire.set_emperor_params(vassals_home='/etc/vassals').
empire.set_mode_broodlord_params(zerg_count=40, vassal_backlog_items_sos=10),
).configure()
# And this one is for zergs.
Section.derive_from(base_section, name='zerg').
workers.set_zerg_client_params(server_sockets=BROODLORD_SOCKET).
master_process.set_idle_params(timeout=30, exit=True)
# Bind Emperor to socket.
emperor.networking.register_socket(Section.networking.sockets.default(':3031'))
])
# Put Emperor and zerg sections into configuration.
multisection_config = Configuration([emperor, zerg])
12 changes: 11 additions & 1 deletion tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

import pytest

from uwsgiconf.utils import UwsgiRunner, parse_command_plugins_output, ConfModule, get_uwsgi_stub_attrs_diff
from uwsgiconf.utils import UwsgiRunner, parse_command_plugins_output, ConfModule, get_uwsgi_stub_attrs_diff, \
filter_locals
from uwsgiconf.exceptions import UwsgiconfException


Expand Down Expand Up @@ -34,6 +35,15 @@
'''


def test_filter_locals():

fake_locals = {'a': 1, 'b': 2, 'c': 3}

assert filter_locals(fake_locals, drop=['a', 'c']) == {'b': 2}
assert filter_locals(fake_locals, include=['a', 'b']) == {'a': 1, 'b': 2}
assert filter_locals(fake_locals, include=['a', 'b'], drop=['b']) == {'a': 1}


def test_parser():
plugins = parse_command_plugins_output(SAMPLE_OUT_PLUGINS_MANY)

Expand Down
8 changes: 8 additions & 0 deletions uwsgiconf/options/empire.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ def set_emperor_params(
stats_address=None, trigger_socket=None, links_no_follow=None):
"""
.. note:: The emperor should generally not be run with master, unless master features like advanced
logging are specifically needed.
.. note:: The emperor should generally be started at server boot time and left alone,
not reloaded/restarted except for uWSGI upgrades;
emperor reloads are a bit drastic, reloading all vassals at once.
Instead vassals should be reloaded individually when needed, in the manner of the imperial monitor in use.
:param str|unicode|list[str|unicode] vassals_home: Set vassals home and enable Emperor mode.
:param str|unicode name: Set the Emperor process name.
Expand Down
74 changes: 74 additions & 0 deletions uwsgiconf/presets/empire.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
from ..config import Section
from ..utils import filter_locals


class Broodlord(object):
"""This mode is a way for a vassal to ask for reinforcements to the Emperor.
Reinforcements are new vassals spawned on demand generally bound on the same socket.
.. warning:: If you are looking for a way to dynamically adapt the number
of workers of an instance, check the Cheaper subsystem - adaptive process spawning mode.
*Broodlord mode is for spawning totally new instances.*
* http://uwsgi-docs.readthedocs.io/en/latest/Broodlord.html
"""
def __init__(
self, zerg_socket, zerg_die_on_idle=None, vassals_home=None,
zerg_count=None, vassal_overload_sos_interval=None, vassal_backlog_items_sos=None,
section_emperor=None, section_zerg=None):
"""
:param str|unicode zerg_socket: Unix socket to bind server to.
:param int zerg_die_on_idle: A number of seconds after which an idle zerg will be destroyed.
:param str|unicode|list[str|unicode] vassals_home: Set vassals home.
:param int zerg_count: Maximum number of zergs to spawn.
:param int vassal_overload_sos_interval: Ask emperor for reinforcement when overloaded.
Accepts the number of seconds to wait between asking for a new reinforcements.
:param int vassal_backlog_items_sos: Ask emperor for sos if backlog queue has more
items than the value specified
"""

self.socket = zerg_socket
self.vassals_home = vassals_home
self.die_on_idle = zerg_die_on_idle
self.broodlord_params = filter_locals(
locals(), include=[
'zerg_count',
'vassal_overload_sos_interval',
'vassal_backlog_items_sos',
])

section_emperor = section_emperor or Section()
section_zerg = section_zerg or Section.derive_from(section_emperor)

self.section_emperor = section_emperor
self.section_zerg = section_zerg

def configure(self):
"""Configures broodlord mode and returns emperor and zerg sections.
:rtype: tuple
"""
section_emperor = self.section_emperor
section_zerg = self.section_zerg

socket = self.socket

section_emperor.workers.set_zerg_server_params(socket=socket)
section_emperor.empire.set_emperor_params(vassals_home=self.vassals_home)
section_emperor.empire.set_mode_broodlord_params(**self.broodlord_params)

section_zerg.name = 'zerg'
section_zerg.workers.set_zerg_client_params(server_sockets=socket)

if self.die_on_idle:
section_zerg.master_process.set_idle_params(timeout=30, exit=True)

return section_emperor, section_zerg
12 changes: 10 additions & 2 deletions uwsgiconf/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,21 +146,29 @@ def listify(src):
return src


def filter_locals(locals_dict, drop=None):
def filter_locals(locals_dict, drop=None, include=None):
"""Filters a dictionary produced by locals().
:param dict locals_dict:
:param list drop: Keys to drop from dict.
:param list include: Keys to include into dict.
:rtype: dict
"""
drop = drop or []
drop.extend([
'self',
'__class__', # py3
])
locals_dict = {k: v for k, v in locals_dict.items() if k not in drop}

include = include or locals_dict.keys()

relevant_keys = [key for key in include if key not in drop]

locals_dict = {k: v for k, v in locals_dict.items() if k in relevant_keys}

return locals_dict


Expand Down

0 comments on commit 36fb796

Please sign in to comment.