{"id":20741194,"url":"https://github.com/bbottema/clustered-object-pool","last_synced_at":"2025-04-24T03:07:59.217Z","repository":{"id":82367776,"uuid":"194446016","full_name":"bbottema/clustered-object-pool","owner":"bbottema","description":"generic-object-pool with added clustering and keyed object pools","archived":false,"fork":false,"pushed_at":"2024-09-15T10:19:59.000Z","size":115,"stargazers_count":2,"open_issues_count":1,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-24T03:07:52.966Z","etag":null,"topics":["clustered-pools","clustering","concurrency","high-performance","java","object-pool","pool","pool-manager"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bbottema.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-2.0.txt","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}},"created_at":"2019-06-29T20:30:24.000Z","updated_at":"2024-10-10T15:40:39.000Z","dependencies_parsed_at":null,"dependency_job_id":"b05587d3-328a-4118-b2a8-9573ffcee2e0","html_url":"https://github.com/bbottema/clustered-object-pool","commit_stats":null,"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bbottema%2Fclustered-object-pool","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bbottema%2Fclustered-object-pool/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bbottema%2Fclustered-object-pool/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bbottema%2Fclustered-object-pool/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bbottema","download_url":"https://codeload.github.com/bbottema/clustered-object-pool/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250552074,"owners_count":21449164,"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":["clustered-pools","clustering","concurrency","high-performance","java","object-pool","pool","pool-manager"],"created_at":"2024-11-17T06:34:57.114Z","updated_at":"2025-04-24T03:07:59.197Z","avatar_url":"https://github.com/bbottema.png","language":"Java","readme":"[![APACHE v2 License](https://img.shields.io/badge/license-apachev2-blue.svg?style=flat)](LICENSE-2.0.txt) \n[![Latest Release](https://img.shields.io/maven-central/v/com.github.bbottema/clustered-object-pool.svg?style=flat)](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.github.bbottema%22%20AND%20a%3A%22clustered-object-pool%22) \n[![Javadocs](https://img.shields.io/badge/javadoc-2.1.1-brightgreen.svg?color=brightgreen)](https://www.javadoc.io/doc/com.github.bbottema/clustered-object-pool) \n[![Codacy](https://img.shields.io/codacy/grade/7a0dc698534d4c9eb459709f7c3fbfe5.svg?style=flat)](https://www.codacy.com/app/b-bottema/clustered-object-pool)\n\n# clustered-object-pool\n\nclustered-object-pool is a lightweight generic clustering object pool, building on generic-object-pool and adding\nkeyed clustered pools.\n\n## Setup\n\nMaven Dependency Setup\n\n```xml\n\u003cdependency\u003e\n\t\u003cgroupId\u003ecom.github.bbottema\u003c/groupId\u003e\n\t\u003cartifactId\u003eclustered-object-pool\u003c/artifactId\u003e\n\t\u003cversion\u003e2.1.1\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n## Usage\n\nThis library builds on top of [generic-object-pool](https://github.com/bbottema/generic-object-pool), which means support for eager/lazy loading and auto expiring objects.\n\nThere are a couple of scenario's you can solve with clustered-object-pool:\n- Have **1 cluster with 1 pool of size 1**. Same as using generic-object-pool directly, where you have one resource, but can share/reuse it among threads.\n- Have **1 cluster with 1 pool of size n**. Same as using generic-object-pool directly, where multiple resources are shared/reused among threads.\n- Have **1 cluster with n pools of size 1**. If you have one cluster with rotating pools to draw a shareable/reusable object from. Usefull when you want to spread load around different servers.\n- Have **1 cluster with n pools of size n**. Same as above, except with multiple objects. For example multiple connections to multiple servers. \n- Have **n clusters ....** Same as all the above except you have dedicated clusters for different purposes. For example a cluster for handling internal mails and a cluster for outgoing mails. \n\nWhen creating clusters, you can optionally preregister pools with specific behavior. \nIf you don't pools and clusters and pools are created on the fly with the provided defaults.\n\n#### Creating clusters\n\nThese examples illustrates this library using SMTP clustering connection pools, \nfor which there is actually a dedicated micro library, [smtp-connection-pool](https://github.com/simple-java-mail/smtp-connection-pool)\n\n```java\n// basic pool with no eager loading and no expiry policy and default round robin pool rotation\nClusterConfig\u003cSession, Transport\u003e clusterConfig = ClusterConfig.\u003cSession, Transport\u003ebuilder()\n    .allocatorFactory(allocatorFactory)\n    .defaultMaxPoolSize(defaultMaxPoolSize)\n    .build();\n\nResourceClusters\u003cUUID, Session, Transport\u003e clusters = new ResourceClusters\u003c\u003e(clusterConfig);\n\nUUID keyCluster1 = UUID.randomUUID();\n\n// claim from cluster, blocking until a resource becomes available\nPoolableObject\u003cTransport\u003e resource = clusters.claimResourceFromCluster(keyCluster1);\n// claim from specific pool, blocking until a resource becomes available\nPoolableObject\u003cTransport\u003e resource = clusters.claimResourceFromPool(new ResourceClusterAndPoolKey\u003c\u003e(keyCluster1, SessionToServerA));\n\n// above cluster and pools are created on the fly\n```\n\n#### Customizing pools\n\n```java\n// the following has the same behavior as not preregistering and registering on the fly when claiming resources\n// it simply uses the global defaults\nclusters.registerResourcePool(new ResourceClusterAndPoolKey\u003c\u003e(keyCluster1, SessionForServerA));\nclusters.registerResourcePool(new ResourceClusterAndPoolKey\u003c\u003e(keyCluster1, SessionForServerB));\n\n// but you can also change individual pool behavior (enabling all the aforementioned scenario's):\nclusters.registerResourcePool(new ResourceClusterAndPoolKey\u003c\u003e(keyCluster1, SessionForServerA),\n    new SpreadedTimeoutSinceLastAllocationExpirationPolicy(5, 10, TimeUnit.SECONDS),\n    10, // core pool size, which means eagerly loading\n    20); // max pool size\nclusters.registerResourcePool(new ResourceClusterAndPoolKey\u003c\u003e(keyCluster1, SessionForServerB));\n````\n\nThe above example creates clusters and pools on the fly as resources are claimed with the appropriate keys, \nexcept for serverA in cluster1: for this server, 10 connections are preloaded with 10 max connections allowed at\nbusy times and with auto expiring connections, disconnection spreading between 5 to 10 seconds after a connection was last used.\n\n#### Providing objects for the clustered pools\n\nNormally you would provide an Allocator to the underlying generic-object-pool, now you provide an AllocatorFactory for\nwhen a new pool is being created.\n\nFor SMTP connections, here's a possible implementation:\n\n```java\nclass TransportAllocatorFactory implements AllocatorFactory\u003cSession, Transport\u003e {\n\t@Override\n\tpublic Allocator\u003cTransport\u003e create(Session session) {\n\t\treturn new TransportAllocator(session);\n\t}\n}\n\nclass TransportAllocator extends Allocator\u003cTransport\u003e {\n\n\tprivate static final Logger LOGGER = getLogger(TransportAllocator.class);\n\n\tprivate final Session session;\n\n\tTransportAllocator(final Session session) {\n\t\tthis.session = session;\n\t}\n\n\t@Override\n\tpublic Transport allocate() {\n\t\tLOGGER.trace(\"opening transport connection...\");\n\t\ttry {\n\t\t\treturn session.getTransport();\n\t\t} catch (NoSuchProviderException e) {\n\t\t\tthrow new RuntimeException(\"unable to get transport from session\", e);\n\t\t}\n\t}\n\t\n\t@Override\n\tpublic void deallocate(Transport transport) {\n\t\tLOGGER.trace(\"closing transport...\");\n\t\ttry {\n\t\t\ttransport.close();\n\t\t} catch (MessagingException e) {\n\t\t\tthrow new RuntimeException(\"error closing transport connection\", e);\n\t\t}\n\t}\n}\n```\nNow each time a specific pool created -either by claiming for it or pre-registering-, this factory is invoked\nwith the respective pool key (the Session instance representing the server).\n\n#### Load balancing strategies\n\nBy default, load is balanced round robin, but you can easily use a different strategy. For example, to use the provided random balancer instead:\n\n```java\nClusterConfig\u003cSession, Transport\u003e clusterConfig = ClusterConfig.\u003cSession, Transport\u003ebuilder()\n    .loadBalancingStrategy(new RandomAccessLoadBalancing())\n    .(..)\n    .build();\n```\n\nThe following balancing strategies are provided by default:\n- RoundRobinCyclingStrategy\n- RandomAccessLoadBalancing\n\nYou can create your own load balancer as well. For example to define a load balancer that routes 50% of the traffic to server A and the other 50% to the rest of the servers, here's one way \nto implement this:\n\n```java\n// load balancer that routes 50% of the traffic to the primary (first) server\npublic class PrimaryServerLoadBalancing\u003cT\u003e implements LoadBalancingStrategy\u003cT, List\u003cT\u003e\u003e {\n\t\n\tpublic List\u003cT\u003e createCollectionForCycling() { return new ArrayList\u003c\u003e(); }\n\t\n\tpublic T cycle(@NotNull List\u003cT\u003e items) {\n\t\tfinal Random rng = ThreadLocalRandom.current();\n\t\titems.get((rng.nextInt(100) \u003c 50) ? 0 : 1 + rng.nextInt(items.size() - 1));\n\t}\n}\n```\n\n## Shutting down\n\n```java\nFuture\u003c?\u003e shutdownFuture = clusters.shutDown();\nFuture\u003c?\u003e shutdownFuture = clusters.shutDown(PoolKey);\n\nshutdownFuture.get(); // blocks until all relevant pools have shut down\n```","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbbottema%2Fclustered-object-pool","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbbottema%2Fclustered-object-pool","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbbottema%2Fclustered-object-pool/lists"}