From b378d180980ac88fef0cd00c7e2454815af5b588 Mon Sep 17 00:00:00 2001 From: Ilan Steemers Date: Fri, 3 Jul 2015 14:42:30 +0200 Subject: [PATCH] Writing sphinx docs --- docs/admin.rst | 2 + docs/architecture.rst | 65 -------------------- docs/cluster.png | Bin 0 -> 45910 bytes docs/cluster.rst | 103 +++++++++++++++++++++++++++++++ docs/conf.py | 5 +- docs/index.rst | 14 ++--- docs/install.rst | 111 ++++++++++++++++++++++++++++++++++ docs/management.rst | 20 ------ docs/monitor.rst | 3 + docs/schedules.rst | 2 + docs/{usage.rst => tasks.rst} | 4 +- 11 files changed, 232 insertions(+), 97 deletions(-) create mode 100644 docs/admin.rst delete mode 100644 docs/architecture.rst create mode 100644 docs/cluster.png create mode 100644 docs/cluster.rst create mode 100644 docs/install.rst delete mode 100644 docs/management.rst create mode 100644 docs/monitor.rst create mode 100644 docs/schedules.rst rename docs/{usage.rst => tasks.rst} (93%) diff --git a/docs/admin.rst b/docs/admin.rst new file mode 100644 index 0000000..1a5c821 --- /dev/null +++ b/docs/admin.rst @@ -0,0 +1,2 @@ +Admin pages +=========== diff --git a/docs/architecture.rst b/docs/architecture.rst deleted file mode 100644 index 0e15ac1..0000000 --- a/docs/architecture.rst +++ /dev/null @@ -1,65 +0,0 @@ - -Architecture ------------- - -.. figure:: http://i.imgur.com/wTIeg2T.png - :alt: Django Q schema - - -Signed Tasks -"""""""""""" - -Tasks are first pickled and then signed using Django's own -signing module before being sent to a Redis list. This ensures that task -packages on the Redis server can only be executed and read by clusters -and django servers who share the same secret key. -Optionally the packages can be compressed before transport - -Pusher -"""""" - -The pusher process continuously checks the Redis list for new task -packages and pushes them on the Task Queue. - -Worker -"""""" - -A worker process checks the package signing, unpacks the task, executes -it and saves the return value. Irrespective of the failure or success of -any of these steps, the package is then pushed onto the Result Queue. - - -Monitor -""""""" - -The result monitor checks the Result Queue for processed packages and -saves both failed and successful packages to the Django database. - - -Sentinel -"""""""" - -The sentinel spawns all process and then checks the health of all -workers, including the pusher and the monitor. Reincarnating processes -if any may fail. In case of a stop signal, the sentinel will halt the -pusher and instruct the workers and monitor to finish the remaining -items , before exiting. see Stop procedure - -Timeouts -"""""""" -Before each task execution the worker resets a timer on the sentinel and resets it again after execution. -Meanwhile the the sentinel checks if the timers don't exceed the timeout amount, in which case it will terminate the worker and reincarnate a new one. - -Hooks -""""" - -Packages can be assigned a hook function, upon completion of the package -this function will be called with the Task object as the first argument. - -Stop procedure -"""""""""""""" - -When a stop signal is given, the sentinel exits the guard loop and instructs the pusher to stop pushing. -Once this is confirmed, the sentinel pushes poison pills onto the task queue and will wait for all the workers to die. -This ensure that the task is emptied before the workers exit. Afterwards the sentinel waits for the monitor to empty the result queue before the stop flow is complete. - diff --git a/docs/cluster.png b/docs/cluster.png new file mode 100644 index 0000000000000000000000000000000000000000..69fb38f80ee3daf6ca62ea6bf875375a36ae6830 GIT binary patch literal 45910 zcmce;Wl$VZ*Di_%clR*3LvSa!1r6>N+}$BT1`iHF6EwlyCAbqHxH}V^!Sy!pIp25d z)U8{$&iQe>YKobj-n)0Nz2sTXT0@kYiW~+iDJl#M42FWdv<3_eTn+G2Lw*CC$?Oq% z{Q|{BUe6r{1`Y4^1q<^nn-~V>EsTQn`;R`^N2}gGAFY-K&z+H(B;*gi{xJwq!+*~S zM@sgCT}xW}TlB$5Et+f^{|_ECkY_p~0gf~*4gu4a2H|^s?DvJF-~Q5u>PN}>VQv~{U5Nn!1|b5B0M-0X(J-6I9o ztp$HiK(f|NBX$p=NHm}pi--zewf;$~T|e7$`?G?BA!k(e8Aqn@y=_1Y zs~ApV_D?XIY&-m;S4p2q+wzpF{N@?v*@GzEv%ZqtpgLo_1B2bn&wV48-VEm5Z6%G% zAZn~2cG;~c@9>RrNK!E?dKli8U%?db@1{FiJUdxsJ(d@@`u{$aWX8w8M;*Sw z!h$7w;in+WcnpV_Pk7CxRq|UYm-J zNyr47KpTUx0|jx~N7b6njd&_^0&9r;E%_NH3_-J_SKw9uFn@mT^v`M_vkr1ksJnCTj(yIe)CJK_`7w1S!jkLi)D+&&++j>;vth${v+DR6u$@IH&=D&^@9DHoaWty(8S4<^N+{S zx;V}LNPJqTcOpHE-)Q+2NzCnz_$T~Sg@gWYu}19uv*< zj1d$gh7FHbmJ`$lH}?ydL-kv4$=*#e26WNKjnT+%f6EjE3Rm6+#O`mqkQjueN3UJ& zc!~&hcaO0uj+p&GC6ZnfQh_5GM+!++XJMEsf)cANI&AMcuIcR18jt@7K?L7>5eGkY z@0r)59s1ThOEnQx540waA+mPM;5w3K(O6&YnJvRL$|5^TPL~bM0*ctaY-wHxrmn+l zYtqZR33|ATMfCC_z23+RWE&J73N6i8ai9Zf9K70p)=%j}B+43alNKLM{aEt%&#UjUp`!1|kn8eUj#joRcms@Pe z!On8eakG1Oyp*KBw;bi7qJ{haA#U5EOZb`nbM$qy#CZYhn&pV!CRg;4FAUcXi7zxb z5jwJ>@x^|c-g;U@vWcg@_wZ{mYOxC^pKCfR@*95xsYyNW>}>^sWL_OpbKVN3gv&80 z!eZWx2wP$$@T$Y!44+Bm4%wnpO84gRPa4Xi;7r3*liaxvoaWfmRuUU`p1cTH? zVo`t%2}b^aX{Rn$!7t1-motzY=?|=*ME_-mBVg z+HNk_iud|`I$rE`+$#d-~RTQ(C4Wf!+ zk~LugBER3M*kQeDT7LnDXBHpKa*YArb@ix-p>ABR8G^MS@_QKX)pblzlYT;K$43oz z{p;YA?ZGYI{M}<34$BrRMRUK$prDo|S?R*+pI`zUe)mvEvKfxjUmxiY4QBP{a>NVq zaL`UX_J0W@pY5yoH_0nE+XT(U`)46pb!hCdV?XoSQlgU4P?wrLIh>|h8E~%a(S2LJ zL3Yr^%HFwck#=euVN)Vn=n{Q;`j`M1JK;Yd5S`F{A}cHB7dcRk<)H^qTmjvl--aWie{cTs*h2l;*C zGpQ7DT@F&Mc%1fwekKhR-ZwOT<7uwDeu*|jFESgY%5S-HdetldtxHyhJP0`Ju1_wt zUrUydV*;SS%m)l+a{dZ0NM z(Ot)#i{x#tg+b@`)gQjG#%mtk$=r@Rs-5+&4^%yDy-qTna%D~yU=iG2z+B2Rcw;f) zt*vXcV1j*lJA`|WI#oHXcAX9{Yj~3(i{25Q_q*>C_L$Syw~KK;

RBI8l3$T~NL( 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 - Usage - Management + Tasks + Schedules + Cluster + Monitor Admin - Architecture - - -* :ref:`genindex` + * :ref:`genindex` * :ref:`search` diff --git a/docs/install.rst b/docs/install.rst new file mode 100644 index 0000000..bbbf12b --- /dev/null +++ b/docs/install.rst @@ -0,0 +1,111 @@ +Installation +============ + +- Install the latest version with pip:: + + $ pip install django-q + + +- Add :mod:`django_q` to your :const:`INSTALLED_APPS` in your projects :file:`settings.py`:: + + INSTALLED_APPS = ( + # other apps + 'django_q', + ) + +- Run Django migrations to create the database tables:: + + $ python manage.py migrate + +- Make sure you have a `Redis `__ server running + somewhere + +Configuration +------------- + +Configuration is handled via the :const:`Q_ClUSTER` dictionary in your :file:`settings.py` + +.. code:: python + + # settings.py example + Q_CLUSTER = { + 'name': 'myproject', + 'workers': 8, + 'recycle': 500, + 'timeout': 60, + 'compress': True, + 'save_limit': 250, + 'label': 'Django Q', + 'redis': { + 'host': '127.0.0.1', + 'port': 6379, + 'db': 0, } + } + + + +name +~~~~ + +Used to differentiate between projects using the same Redis server. Defaults to ``'default'``. +This can be useful if you have several projects using the same Redis server. + +.. note:: + Tasks are encrypted. When a worker encounters a task it can not decrypt, it will be discarded + +workers +~~~~~~~ + +The number of workers to use in the cluster. Defaults to CPU count of the current host, but can be set to a custom number. + +recycle +~~~~~~~ + +The number of tasks a worker will process before respawning. Useful to release resources on a regular basis. Defaults to ``500``. + +timeout +~~~~~~~ + +The number of seconds a worker is allowed to spend on a task before it's terminated. Defaults to ``None``, meaning it will never time out. +Set this to something that makes sense for your use + +compress +~~~~~~~~ + +Compress task packages to Redis. Useful for large payloads, but can add overhead when used with many small packages. +Defaults to ``False`` + +save_limit +~~~~~~~~~~ + +Limits the amount of successful tasks saved to Django. +Set to ``0`` for unlimited. Set to ``-1`` for no success storage at all. +Failures are always saved. Defaults to ``250`` + +label +~~~~~ + +The label used for the Django Admin page. Defaults to ``'Django Q'`` + +redis +~~~~~ + +Connection settings for Redis. Defaults:: + + redis: { + 'host': 'localhost', + 'port': 6379, + 'db': 0, + 'password': None, + 'socket_timeout': None, + 'charset': 'utf-8', + 'errors': 'strict', + 'unix_socket_path': None + } + +For more information on these settings please refer to the `Redis-py `__ documentation + + +.. note:: + Django Q uses your :const:`SECRET_KEY` to encrypt task packages and prevent task crossover. So make sure you have it set up in your Django settings. + diff --git a/docs/management.rst b/docs/management.rst deleted file mode 100644 index 88e1859..0000000 --- a/docs/management.rst +++ /dev/null @@ -1,20 +0,0 @@ -Management commands -=================== - -$project offers the following Django management commands - - -qcluster --------- - -.. code:: bash - - python management.py qcluster - - -qmonitor --------- - -.. code:: bash - - python management.py qmonitor diff --git a/docs/monitor.rst b/docs/monitor.rst new file mode 100644 index 0000000..e962a1a --- /dev/null +++ b/docs/monitor.rst @@ -0,0 +1,3 @@ +Monitor +======= + diff --git a/docs/schedules.rst b/docs/schedules.rst new file mode 100644 index 0000000..867fa68 --- /dev/null +++ b/docs/schedules.rst @@ -0,0 +1,2 @@ +Schedules +========= diff --git a/docs/usage.rst b/docs/tasks.rst similarity index 93% rename from docs/usage.rst rename to docs/tasks.rst index 4132f4f..1a96ce4 100644 --- a/docs/usage.rst +++ b/docs/tasks.rst @@ -1,7 +1,7 @@ -Usage +Tasks ===== -Use :py:func:`async` from your code to quickly offload tasks: +Use :py:func:`async` from your code to quickly offload tasks to the py:module:`cluster`: .. code:: python