{"id":32195371,"url":"https://github.com/20centaurifux/severin","last_synced_at":"2026-07-13T06:31:34.049Z","repository":{"id":62435276,"uuid":"102287124","full_name":"20centaurifux/severin","owner":"20centaurifux","description":"A Clojure API for implementing resource pooling.","archived":false,"fork":false,"pushed_at":"2023-02-25T09:30:31.000Z","size":74,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-11-22T03:11:03.076Z","etag":null,"topics":["clojure","pooling"],"latest_commit_sha":null,"homepage":null,"language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/20centaurifux.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2017-09-03T18:56:35.000Z","updated_at":"2023-02-25T09:22:48.000Z","dependencies_parsed_at":"2025-10-22T02:38:27.220Z","dependency_job_id":"509a4215-e1d0-4745-8b73-2e1ea49a2acf","html_url":"https://github.com/20centaurifux/severin","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/20centaurifux/severin","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/20centaurifux%2Fseverin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/20centaurifux%2Fseverin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/20centaurifux%2Fseverin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/20centaurifux%2Fseverin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/20centaurifux","download_url":"https://codeload.github.com/20centaurifux/severin/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/20centaurifux%2Fseverin/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35413537,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-13T02:00:06.543Z","response_time":119,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["clojure","pooling"],"created_at":"2025-10-22T02:09:56.564Z","updated_at":"2026-07-13T06:31:34.038Z","avatar_url":"https://github.com/20centaurifux.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# severin\n\n## Introduction\n\n*severin* provides a Clojure API for implementing resource pools, such as\nnetwork and database connections.\n\n## Installation\n\nThe library can be installed from Clojars using Leiningen:\n\n[![Clojars Project](http://clojars.org/zcfux/severin/latest-version.svg)](https://clojars.org/zcfux/severin)\n\n\n## Creating and releasing resources\n\nResources have an associated URI. They are created and placed back in pool\nwith *create!* and *dispose!*.\n\n```\n(defn pool (make-pool))\n\n(let [r (create! pool \"monger://localhost\")]\n  ; do something\n  (dispose! pool r))\n```\n\n*with-pool* evaluates a body in a try expression. Created resources are bound\nto names. The finally clause calls *dispose!* on each name.\n\n```\n(with-pool pool [db \"monger://localhost\"\n                 file \"file:///tmp/helloworld.txt\"]\n ; do something\n)\n```\n\n## Resource lifecycle\n\nThe lifecycle of every resource type is managed by a factory.\n\n```\n(defprotocol FactoryProtocol\n  (-create!\n    [this uri]\n    \"Creates a new resource from a URI.\")\n\n  (-dispose!\n    [this resource]\n    \"Disposes a resource.\")\n\n  (-recycle!\n    [this resource uri]\n    \"Recycles an existing resource and assigns a URI.\")\n\n  (-valid?\n    [this resource]\n    \"Tests if a resource is still valid.\"))\n```\n\nThe *make-factory* multimethod creates a factory from a URI by dispatching on the\nscheme.\n\n```\n(defmulti make-factory\n  \"Creates a factory from a URI by dispatching on the scheme.\"\n  #(-\u003e %\n       java.net.URI.\n       .getScheme))\n```\n\n## Pool internals\n\nA pool is a *Ref* holding a map. It can be created with *make-pool*.\n\nDisposed resources are pushed onto a queue. Queues are grouped by resource\nURIs. This association can be customized by implementing the\n*URI-\u003eKeyProtocol*.\n\n```\n(defprotocol URI-\u003eKeyProtocol\n  (-uri-\u003ekey\n    [this uri]\n    \"Converts a URI to a keyword.\"))\n```\n\nWhen implementing a pool for network connections like HTTP you might want to\ngroup resources by hostname instead of the full URI.\n\n```\n(defrecord \n\n  [...]\n\n  URI-\u003eKeyProtocol\n  (-uri-\u003ekey\n    [this uri]\n    (-\u003e uri\n        java.net.URI.\n        .getHost\n        keyword)))\n```\n\n## Factory example\n\nIn this example we implement a pool for file input streams.\n\n```\n(ns severin.example\n  (:require [severin.core :refer :all]))\n\n(defrecord FileReaderFactory []\n  FactoryProtocol\n  (-create!\n    [this uri]\n    (let [resource (clojure.java.io/make-input-stream uri {})]\n      (.mark resource 0)\n      resource))\n\n (-dispose!\n    [this resource]\n    (.close resource))\n\n  (-recycle!\n    [this resource uri]\n    (.reset resource)\n    resource)\n\n  (-valid?\n    [this resource]\n    true))\n\n(defmethod make-factory \"file\"\n  [uri]\n  (FileReaderFactory.))\n```\n\nCreating a stream for the very first time a mark is set. The cursor is\npositioned to the beginning of the file when a resource is recycled.\n\nLet's create a pool and open a file.\n\n```\n=\u003e (def pool (make-pool :max-size 5)) ; queues can grow up to 5 resources\n=\u003e (def s (create! pool \"file:///tmp/some/file\"))\n```\n\nEverything looks fine until you place back the resource in pool.\n\n```\n=\u003e (dispose! pool s)\n=\u003e IllegalArgumentException Couldn't get URI from resource.\n```\n\nWhat happened here? As described before factories are created by dispatching\non the scheme. Therefore you have to specify the URI if it's not provided by\nthe resource itself.\n\n```\n=\u003e (dispose! pool \"file:///tmp/some/file\" s)\n```\n\nYou can fix this by adding a custom resource type which implements *URIProtocol*.\n\n```\n(ns severin.filereader\n  (:gen-class\n   :extends java.io.BufferedInputStream\n   :init init\n   :state state\n   :constructors {[String][java.io.InputStream]})\n   (:require [severin.core :refer [URIProtocol -uri]]))\n\n(defn -init\n  [uri]\n  [[(-\u003e uri\n        java.net.URI.\n        .getPath\n        clojure.java.io/as-file\n        java.io.FileInputStream.)]\n   uri])\n\n(extend severin.filereader\n  URIProtocol\n  {:-uri #(.state %)})\n```\n\nAfter updating the factory you can dispose resources without specifying the\nURI.\n\n```\n=\u003e (dispose! pool s)\n```\n\nIf a resource doesn't implement *URIProtocol* *severin* tries to lookup :uri.\nThis makes it possible to use maps instead of custom types.\n\n```\n(defrecord FileReaderFactory []\n  FactoryProtocol\n  (-create!\n    [this uri]\n    (let [stream (clojure.java.io/make-input-stream uri {})]\n      (.mark stream 0)\n      {:uri uri\n       ::stream stream}))\n\n  [...])\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F20centaurifux%2Fseverin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F20centaurifux%2Fseverin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F20centaurifux%2Fseverin/lists"}