{"id":22334501,"url":"https://github.com/adambien/porcupine","last_synced_at":"2025-07-29T21:31:16.067Z","repository":{"id":25574884,"uuid":"29008657","full_name":"AdamBien/porcupine","owner":"AdamBien","description":"Threading, Resiliency and Monitoring for Java EE 7/8","archived":false,"fork":false,"pushed_at":"2016-12-23T15:42:44.000Z","size":102,"stargazers_count":96,"open_issues_count":2,"forks_count":22,"subscribers_count":13,"default_branch":"master","last_synced_at":"2023-07-26T21:12:53.720Z","etag":null,"topics":["cloud","cloud-native","executorservice","injectable-statistics","java","microservices","monitoring","overload","porcupine","resiliency","statistics","threading"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AdamBien.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":"2015-01-09T08:54:07.000Z","updated_at":"2023-07-05T17:05:19.000Z","dependencies_parsed_at":"2022-07-10T12:16:43.839Z","dependency_job_id":null,"html_url":"https://github.com/AdamBien/porcupine","commit_stats":null,"previous_names":[],"tags_count":5,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AdamBien%2Fporcupine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AdamBien%2Fporcupine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AdamBien%2Fporcupine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AdamBien%2Fporcupine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AdamBien","download_url":"https://codeload.github.com/AdamBien/porcupine/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228046869,"owners_count":17861109,"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":["cloud","cloud-native","executorservice","injectable-statistics","java","microservices","monitoring","overload","porcupine","resiliency","statistics","threading"],"created_at":"2024-12-04T05:08:09.212Z","updated_at":"2024-12-04T05:08:09.735Z","avatar_url":"https://github.com/AdamBien.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# porcupine\nConfigurable threading, resiliency and monitoring with injectable statistics for Java EE 7. Porcupine is the implementation of the [bulkhead](https://johnragan.wordpress.com/2009/12/08/release-it-stability-patterns-and-best-practices/) and [handshaking](https://johnragan.wordpress.com/2009/12/08/release-it-stability-patterns-and-best-practices/) patterns for Java EE 7.\n\nFeatures:\n\n1. Conventional: ExecutorService is directly injectable. The thread pool derives the name from the field, but can be easily overridden.\n2. Drop-in install: a single dependency in the pom.xml is sufficient. \n3. Standard based: porcupine uses [JSR 236: Concurrency Utilities for JavaTM EE](https://www.jcp.org/en/jsr/detail?id=236)\n4. Small: the entire framework is: 16kB.\n5. Extensible without configuration: All major components can be replaced (big thanks to [@Specializes](http://docs.oracle.com/javaee/7/api/javax/enterprise/inject/Specializes.html))\n\n### Booting Porcupine\n[![Intro](https://i.ytimg.com/vi/20KVZ0ZnCl4/mqdefault.jpg)](https://www.youtube.com/embed/20KVZ0ZnCl4?rel=0)\n\n### Configuration\n[![Configuration](https://i.ytimg.com/vi/4M1EJntwjk8/mqdefault.jpg)](https://www.youtube.com/embed/4M1EJntwjk8?rel=0)\n### Dealing with Overload\n[![Overload](https://i.ytimg.com/vi/HToJuV28pPI/mqdefault.jpg)](https://www.youtube.com/embed/HToJuV28pPI?rel=0)\n\n### Automatic Statistics Injection\n[![Overload](https://i.ytimg.com/vi/0slZph_LC0A/mqdefault.jpg)](https://www.youtube.com/embed/0slZph_LC0A?rel=0)\n\n##Installation\n\n```\n        \u003cdependency\u003e\n            \u003cgroupId\u003ecom.airhacks\u003c/groupId\u003e\n            \u003cartifactId\u003eporcupine\u003c/artifactId\u003e\n            \u003cversion\u003eNEWEST_VERSION\u003c/version\u003e\n            \u003cscope\u003ecompile\u003c/scope\u003e\n        \u003c/dependency\u003e\n```\nWith statistics injection into HTTP headers of all JAX-RS resources:\n\n```\n        \u003cdependency\u003e\n            \u003cgroupId\u003ecom.airhacks\u003c/groupId\u003e\n            \u003cartifactId\u003eporcupine-spy\u003c/artifactId\u003e\n            \u003cversion\u003eNEWEST_VERSION\u003c/version\u003e\n            \u003cscope\u003ecompile\u003c/scope\u003e\n        \u003c/dependency\u003e\n```\n\n##Conventional Usage\n\n```\n@Stateless\npublic class MessagesService {\n\n    @Inject\n    @Dedicated\n    ExecutorService light;\n\n    @Inject\n    @Dedicated\n    ExecutorService heavy;\n```\n\nCustom naming is also supported:\n```\n    @Inject\n    @Dedicated(\"custom-pool\")\n    private ExecutorService first;\n```\n\n##Statistics and monitoring\n\n###Exposure\n\n\t@Path(\"statistics\")\n\t@RequestScoped\n\t@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})\n\tpublic class StatisticsResource {\n\n\t    @Inject\n\t    Instance\u003cList\u003cStatistics\u003e\u003e statistics;\n\n    \t@GET\n\t    public List\u003cStatistics\u003e expose() {\n\t        return this.statistics.get();\n    \t}\n\n\t}\n\t\n###Sample output\n\nUnified thread pool statistics are accessible via injection. Individual statistics are injectable with the `@Dedicated` qualifier.\n\nXML statistics\n\n```\n\u003cstatistics\u003e\n\t\u003cpipelineName\u003elight\u003c/pipelineName\u003e\n\t\u003cremainingQueueCapacity\u003e100\u003c/remainingQueueCapacity\u003e\n\t\u003ccompletedTaskCount\u003e1\u003c/completedTaskCount\u003e\n\t\u003cactiveThreadCount\u003e0\u003c/activeThreadCount\u003e\n\t\u003clargestThreadPoolSize\u003e1\u003c/largestThreadPoolSize\u003e\n\t\u003ccurrentThreadPoolSize\u003e1\u003c/currentThreadPoolSize\u003e\n\t\u003ctotalNumberOfTasks\u003e1\u003c/totalNumberOfTasks\u003e\n\t\u003cmaximumPoolSize\u003e48\u003c/maximumPoolSize\u003e\n\t\u003crejectedExecutionHandlerName\u003eExecutorServiceExposer$$Lambda$3/1562863014\u003c/rejectedExecutionHandlerName\u003e\n\t\u003crejectedTasks\u003e0\u003c/rejectedTasks\u003e\n\u003c/statistics\u003e\n\u003cstatistics\u003e\n\t\u003cpipelineName\u003eheavy\u003c/pipelineName\u003e\n\t\u003cremainingQueueCapacity\u003e16\u003c/remainingQueueCapacity\u003e\n\t\u003ccompletedTaskCount\u003e0\u003c/completedTaskCount\u003e\n\t\u003cactiveThreadCount\u003e1\u003c/activeThreadCount\u003e\n\t\u003clargestThreadPoolSize\u003e1\u003c/largestThreadPoolSize\u003e\n\t\u003ccurrentThreadPoolSize\u003e1\u003c/currentThreadPoolSize\u003e\n\t\u003ctotalNumberOfTasks\u003e1\u003c/totalNumberOfTasks\u003e\n\t\u003cmaximumPoolSize\u003e8\u003c/maximumPoolSize\u003e\n\t\u003crejectedExecutionHandlerName\u003eCallerRunsPolicy\u003c/rejectedExecutionHandlerName\u003e\n\t\u003crejectedTasks\u003e0\u003c/rejectedTasks\u003e\n\u003c/statistics\u003e\n```\nJSON statistics\n```\n[{\n        \"pipelineName\": \"light\",\n        \"remainingQueueCapacity\": 100,\n        \"completedTaskCount\": 1,\n        \"activeThreadCount\": 0,\n        \"largestThreadPoolSize\": 1,\n        \"currentThreadPoolSize\": 1,\n        \"totalNumberOfTasks\": 1,\n        \"maximumPoolSize\": 48,\n        \"rejectedExecutionHandlerName\": \"ExecutorServiceExposer$$Lambda$3/1562863014\",\n        \"rejectedTasks\": 0\n    },\n    {\n        \"pipelineName\": \"heavy\",\n        \"remainingQueueCapacity\": 16,\n        \"completedTaskCount\": 1,\n        \"activeThreadCount\": 0,\n        \"largestThreadPoolSize\": 1,\n        \"currentThreadPoolSize\": 1,\n        \"totalNumberOfTasks\": 1,\n        \"maximumPoolSize\": 8,\n        \"rejectedExecutionHandlerName\": \"CallerRunsPolicy\",\n        \"rejectedTasks\": 0\n    }]\n```\n## Custom configuration (fully optional)\n\n```\n@Specializes\npublic class CustomExecutorConfigurator extends ExecutorConfigurator {\n\n    @Override\n    public ExecutorConfiguration defaultConfigurator() {\n        return super.defaultConfigurator();\n    }\n\n    @Override\n    public ExecutorConfiguration forPipeline(String name) {\n        if (\"heavy\".equals(name)) {\n            return new ExecutorConfiguration.Builder().\n                    corePoolSize(4).\n                    maxPoolSize(8).\n                    queueCapacity(16).\n                    keepAliveTime(1).\n                    callerRunsPolicy().\n                    build();\n        }\n        return super.forPipeline(name);\n    }\n\n}\n```\n\n## Statistics Injection into HTTP Headers\n\n```\nHTTP/1.1 200 OK\nServer: GlassFish Server Open Source Edition  4.1 \nX-Powered-By: Servlet/3.1 JSP/2.3 (GlassFish Server Open Source Edition  4.1  Java/Oracle Corporation/1.8)\n```\n```json\nx-porcupine-statistics-light: {\"pipelineName\":\"light\",\"activeThreadCount\":1,\"completedTaskCount\":1,\n\"corePoolSize\":8,\"currentThreadPoolSize\":2,\"largestThreadPoolSize\":2,\"maximumPoolSize\":16,\"rejectedTasks\":0,\n\"remainingQueueCapacity\":100,\"minQueueCapacity\":100,\"totalNumberOfTasks\":2}\nx-porcupine-statistics-heavy: {\"pipelineName\":\"heavy\",\"rejectedExecutionHandlerName\":\"CallerRunsPolicy\",\n\"activeThreadCount\":0,\"completedTaskCount\":1,\"corePoolSize\":4,\"currentThreadPoolSize\":1,\n\"largestThreadPoolSize\":1,\"maximumPoolSize\":8,\"rejectedTasks\":0,\"remainingQueueCapacity\":16,\n\"minQueueCapacity\":16,\"totalNumberOfTasks\":1}\n```\n```\nContent-Type: text/plain\nDate: Wed, 18 Mar 2015 07:50:20 GMT\nContent-Length: 36\n```\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadambien%2Fporcupine","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fadambien%2Fporcupine","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadambien%2Fporcupine/lists"}