{"id":15337260,"url":"https://github.com/vy/patron","last_synced_at":"2025-10-16T13:30:37.213Z","repository":{"id":558339,"uuid":"189155","full_name":"vy/patron","owner":"vy","description":"A multi-consumer/multi-producer  thread pooling  library for Common Lisp.","archived":false,"fork":false,"pushed_at":"2013-04-12T13:47:00.000Z","size":120,"stargazers_count":15,"open_issues_count":0,"forks_count":1,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-12-06T15:22:07.573Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Common Lisp","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vy.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2009-04-30T07:04:11.000Z","updated_at":"2024-03-23T16:09:29.000Z","dependencies_parsed_at":"2022-07-07T14:17:54.246Z","dependency_job_id":null,"html_url":"https://github.com/vy/patron","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vy%2Fpatron","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vy%2Fpatron/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vy%2Fpatron/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vy%2Fpatron/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vy","download_url":"https://codeload.github.com/vy/patron/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":236721582,"owners_count":19194454,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-01T10:20:19.434Z","updated_at":"2025-10-16T13:30:36.853Z","avatar_url":"https://github.com/vy.png","language":"Common Lisp","funding_links":[],"categories":[],"sub_categories":[],"readme":"           ____   ____ ______ ____   ___  ____\n    !!  ! |    \\ /    |      T    \\ /   \\|    \\  !!!!\n    !!!   |  o  Y  o  |      |  D  Y     Y  _  l  ! !!!\n    !!!!  |   _/|     l_   __j     |  O  |  |  |   !!!!\n    !!:   |  |  |  _  | |  | |    \\|     |  |  |  !: :!\n    :!:   |  |  |  |  | |  | |  .  l     !  |  |   : ::\n     ::   l__j  l__j__j l__j l__j\\_j\\___/l__j__j   :  :\n\n# Abstract\n\nPatron is a multi-consumer/multi-producer thread pooling library written in Common Lisp with flexibility and performance in mind. You simply create a `PATRON` with a job queue of fixed size, specify a fixed number of `WORKER` threads and start submitting your `JOB`s into the work queue.\n\nWhile Patron is written in portable Common Lisp in mind, because of some platform specific features[1], it currently works on [SBCL](http://www.sbcl.org/) and [CCL](http://openmcl.clozure.com/) platforms.  As a side note, Patron currently depends on [bordeaux-threads](http://common-lisp.net/project/bordeaux-threads/) library for common threading functionalities.\n\n[1] Semaphores, missing threading features (`THREAD-JOIN`, `WITHOUT-INTERRUPTS`, etc.) in bordeaux-threads, `WITH-TIMEOUT` macro.\n\n# Example\n\nBelow  basic example should  get you  to a  point where  you can  start creating thread pools in minutes.\n\n    (defvar *stream* *standard-output*)\n    \n    (defvar *stream-lock* (patron:make-lock))\n    \n    (defun safe-format (fmt \u0026rest args)\n      (patron:with-lock *stream-lock*\n        (apply #'format *stream* fmt args)))\n    \n    (defun thread-stats (patron)\n      (safe-format\n       \"Keepers: ~{~A~^ ~}~%Workers: ~{~A~^ ~}~%\"\n       (map 'list #'patron:thread-alive-p (patron::keepers-of patron))\n       (map 'list #'patron:thread-alive-p (patron::workers-of patron))))\n    \n    (let ((state (make-random-state)))\n      (defun job ()\n        (let ((duration (random 5 state)))\n          (safe-format \"  ~S =\u003e Sleeping... [~A]~%\" (patron:current-thread) duration)\n          (sleep duration)\n          (safe-format \"  ~S =\u003e Done!~%\" (patron:current-thread)))))\n    \n    (defun report-result (job)\n      (safe-format \"RESULT: JOB: ~S~%\" job))\n    \n    (defun patron-test ()\n      (let* ((patron\n              (make-instance\n               'patron:patron\n               :worker-capacity 3\n               :job-capacity 32\n               :worker-timeout-duration 3)))\n        (safe-format \"Starting...~%\")\n        (patron:start-patron patron)\n        (sleep 1.0)\n        (thread-stats patron)\n        (safe-format \"Submitting jobs...~%\")\n        (loop repeat 5\n              do (patron:submit-job\n                  patron\n                  (make-instance\n                       'patron:job\n                       :function #'job\n                       :result-report-function #'report-result)))\n        (safe-format \"Submitted.~%\")\n        (safe-format \"Stopping...~%\")\n        (patron:stop-patron patron :wait t)\n        (safe-format \"Stopped.~%\")\n        (thread-stats patron)))\n    \n    ; Starting...\n    ; Keepers: T T\n    ; Workers: T T T\n    ; Submitting jobs...\n    ; Submitted.\n    ; Stopping...\n    ;   #\u003cSB-THREAD:THREAD \"Anonymous\" RUNNING {10040E8D21}\u003e =\u003e Sleeping... [2]\n    ;   #\u003cSB-THREAD:THREAD \"Anonymous\" RUNNING {10040E8F71}\u003e =\u003e Sleeping... [2]\n    ;   #\u003cSB-THREAD:THREAD \"Anonymous\" RUNNING {10040EA1D1}\u003e =\u003e Sleeping... [3]\n    ;   #\u003cSB-THREAD:THREAD \"Anonymous\" RUNNING {10040E8D21}\u003e =\u003e Done!\n    ; RESULT: JOB: #\u003cPATRON:JOB :FUNCTION #\u003cFUNCTION TEST::JOB\u003e :START-TIME \"2009-04-30 14:41:49\" :FINISH-TIME \"2009-04-30 14:41:51\" {1004155561}\u003e\n    ;   #\u003cSB-THREAD:THREAD \"Anonymous\" RUNNING {10040E8D21}\u003e =\u003e Sleeping... [3]\n    ;   #\u003cSB-THREAD:THREAD \"Anonymous\" RUNNING {10040E8F71}\u003e =\u003e Done!\n    ; RESULT: JOB: #\u003cPATRON:JOB :FUNCTION #\u003cFUNCTION TEST::JOB\u003e :START-TIME \"2009-04-30 14:41:49\" :FINISH-TIME \"2009-04-30 14:41:51\" {1004155891}\u003e\n    ;   #\u003cSB-THREAD:THREAD \"Anonymous\" RUNNING {10040E8F71}\u003e =\u003e Sleeping... [2]\n    ; 2009-04-30 14:41:52 - #\u003cPATRON:JOB :FUNCTION #\u003cFUNCTION TEST::JOB\u003e :START-TIME \"2009-04-30 14:41:49\" :CONDITION #\u003cPATRON::TIMEOUT-CONDITION :DURATION 3 :TIME \"2009-04-30 14:41:52\"\u003e {1004155BC1}\u003e\n    ;   #\u003cSB-THREAD:THREAD \"Anonymous\" RUNNING {10040E8F71}\u003e =\u003e Done!\n    ; RESULT: JOB: #\u003cPATRON:JOB :FUNCTION #\u003cFUNCTION TEST::JOB\u003e :START-TIME \"2009-04-30 14:41:51\" :FINISH-TIME \"2009-04-30 14:41:53\" {1004156231}\u003e\n    ; 2009-04-30 14:41:54 - #\u003cPATRON:JOB :FUNCTION #\u003cFUNCTION TEST::JOB\u003e :START-TIME \"2009-04-30 14:41:51\" :CONDITION #\u003cPATRON::TIMEOUT-CONDITION :DURATION 3 :TIME \"2009-04-30 14:41:54\"\u003e {1004155EF1}\u003e\n    ; Stopped.\n    ; Keepers: NIL NIL\n    ; Workers: NIL NIL NIL\n\n# Documentation\n\nBefore going  into the syntatical  details, here is  a general figure  about the inner workings of Patron.\n\n* Queue operations take action in a blocking manner and are wrapped by `WITH-TIMEOUT` statements.\n* There are no busy waits, synchronized access is supplied using semaphores.\n* Using a two-lock concurrent queue algorithm, consumer and producer lockings are separated from each other for performance purposes .\n* There are two keeper threads where each keeper is ensuring its partners existence and first (master) keeper ensuring the existence of specified number of worker threads.\n\nWhile Patron source code is fully documented, below you'll find the documentation excerpts from the source code for exported symbols.\n\n    [Condition] timeout-condition (error-condition)\n      [Slot] time - Time condition instance is created.\n      [Slot] duration - Elapsed duration before condition is raised.\n\n\u003e Condition  thrown  when  the  duration  specified  in  the  `WITH-TIMEOUT`  is exceeded. (`TIME` slot is inherited from `ERROR-CONDITION`.)\n\n    [Function] default-error-report (condition)\n\n\u003e Default function for reporting errors.\n\n    [Class] thread ()\n      [Slot] id - Implementation dependent thread identifier.\n      [Slot] function - Function executed by current thread.\n\n    [Function] make-lock ()\n\n    [Macro] with-lock (lock \u0026body body)\n\n    [Function] thread-start (thread)\n\n    [Function] current-thread ()\n\n    [Function] thread-alive-p (thread)\n\n    [Function] thread-interrupt (thread function)\n\n    [Function] thread-join (thread)\n\n    [Macro] without-interrupts (\u0026body body)\n\n    [Class] job ()\n      [Slot] function - Function will be called to start the execution.\n      [Slot] result-report-function - Function will be called to report the result.\n      [Slot] error-report-function - Function will be called to report an error.\n      [Slot] submit-time - Job queue entrance time.\n      [Slot] start-time - Job execution start time.\n      [Slot] finish-time - Job execution finish time.\n      [Slot] condition - Signaled condition in case of a failure.\n      [Slot] result - Job result in case of no failure.\n\n    [Class] patron ()\n      [Slot] error-report-function - Will get called for management related\n             errors -- e.g when found a dead worker, keeper, etc.\n      [Slot] job-capacity - Upper limit on the job queue size.\n      [Slot] worker-capacity - Number of serving `WORKER's.\n      [Slot] worker-timeout-duration - Time limit on the work processing duration.\n      [Slot] keeper-timeout-duration - Wait period for keepers.\n\n    [Function] submit-job (patron job)\n\n\u003e Submit given `JOB` into the job queue of `PATRON`. Function works in a blocking manner and returns inserted `JOB`, or throws a `TIMEOUT-CONDITION`.\n\n    [Function] worker-stats (patron)\n\n\u003e Returns a property list of minimum, maximum, and average statistics of `N-FAILURES`, `FAIL-DURATION`, `BUSY-DURATION`, and `IDLE-DURATION` slots among workers. Function blocks job queue while gathering statistics.\n\n    [Function] start-patron (patron)\n\n\u003e After switching `STATE` to `:ACTIVE`, starts `WORKERS`s and `KEEPER`s in order.\n\n    [Function] stop-patron (patron \u0026key wait kill)\n\n\u003e After switching `STATE` to `:INACTIVE`, stops `KEEPER`s and `WORKER`s in order. For related effects of keyword arguments see documentation of `STOP-KEEPERS` and `STOP-WORKERS` functions.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvy%2Fpatron","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvy%2Fpatron","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvy%2Fpatron/lists"}