{"id":21447870,"url":"https://github.com/hsbc/cranker-connector","last_synced_at":"2025-07-14T20:30:55.311Z","repository":{"id":39482392,"uuid":"506584771","full_name":"hsbc/cranker-connector","owner":"hsbc","description":"A Cranker connector for Java as a library that has no external dependencies.","archived":false,"fork":false,"pushed_at":"2024-04-12T08:20:30.000Z","size":289,"stargazers_count":23,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-04-30T11:36:50.500Z","etag":null,"topics":[],"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/hsbc.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}},"created_at":"2022-06-23T09:54:43.000Z","updated_at":"2024-02-19T08:57:57.000Z","dependencies_parsed_at":"2024-04-11T03:06:23.517Z","dependency_job_id":null,"html_url":"https://github.com/hsbc/cranker-connector","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hsbc%2Fcranker-connector","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hsbc%2Fcranker-connector/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hsbc%2Fcranker-connector/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hsbc%2Fcranker-connector/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hsbc","download_url":"https://codeload.github.com/hsbc/cranker-connector/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225994783,"owners_count":17556830,"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-11-23T03:12:31.394Z","updated_at":"2025-07-14T20:30:55.297Z","avatar_url":"https://github.com/hsbc.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"cranker-connector\n=================\n\nA cranker connector that has no external dependencies. Requires JDK11 or later.\n\nBackground\n----------\n\nCranker is a load-balancing reverse proxy designed for systems with many HTTP services that need to\nbe exposed at a single endpoint. It was designed for fast-moving teams that need to deploy early and often\nwith no central configuration needed when a new service is introduced or an existing one is upgraded.\n\nThe key difference with other reverse proxies and load balancers is that each service connects via a \"connector\"\nto one or more routers. This connection between connector and router is a websocket, and crucially it means\nthe service is self-configuring; the router knows where a service is and if it is available by the fact that\nit has an active websocket connection for a service.\n\nAlthough there are websockets in the middle, from the point of view of clients and the target microservices,\neverything is standard HTTP, and any HTTP libraries can be used.\n\nFor Java-based services, a connector can be embedded into the service by using a connector library, such\nas this one.\n\nUsage\n-----\n\nIn this scenario, you have a microservice that you want to expose on a list of existing cranker routers.\n\n1. Add a dependency to this library:\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.hsbc.cranker\u003c/groupId\u003e\n    \u003cartifactId\u003ecranker-connector\u003c/artifactId\u003e\n    \u003cversion\u003eRELEASE\u003c/version\u003e\n\u003c/dependency\u003e\n```\n2. In your service, start a web server using your preferred framework. This will only be accessed over\n   a local connection, so the port number is not important (so port 0 is recommended), and you can bind to the\n   localhost network interface which is recommended for security reasons.\n3. Create a `CrankerConnector` object, passing it the router URLs and your service's URL.\n    ````java\n    URI targetServiceUri = startedWebServerUri();\n    \n    CrankerConnector connector = CrankerConnectorBuilder.connector()\n        .withRouterLookupByDNS(URI.create(\"wss://my-router.example.org:8008\"))\n        .withRoute(\"path-prefix\")\n        .withTarget(targetServiceUri)\n        .start();\n    ````\n\nYour service will now be available on the cranker router.\n\nIf you have multiple routers then a single domain name can point to all instances of your router. The `withRouterLookupByDNS`\nmethod will result in a periodic DNS lookup to resolve the router IP addresses. Note that using this approach will use\nIP-address URLs which may affect SNI and/or hostname verification. Using fixed DNS names if that's an issue or see the SSL\nsection below for a workaround.\n\nListening to events\n-------------------\n\nIf you want to know things like why your connector cannot connect to a router, or see when the registration URLs\nchange, you can listen:\n\n````java\nCrankerConnectorBuilder.connector()\n    .withRouterRegistrationListener(new RouterEventListener() {\n       public void onRegistrationChanged(ChangeData data) {\n           log.info(\"Router registration changed: \" + data);\n       }\n       public void onSocketConnectionError(RouterRegistration router, Throwable exception) {\n           log.warn(\"Error connecting to \" + router, exception);\n       }\n    })\n````\n\nSecurity Considerations\n-----------------------\n\nIf the routers being connected to do not trust all connections on the cranker registration port, you must apply\nauthentication on the connectors to ensure only authorized connectors can serve traffic.\n\nAny TCP or HTTP authentication scheme can be used, including basic or token authentication, mTLS, or IP validation. For\nmTLS the HTTP Client supplied to the connector builder should include the client certificate to use.\n\nFor HTTP header-based authentication schemes, there is a registration listener available that can be used to inject\nvalues into the websocket request that is made to establish new routes on the router:\n\n```java\nCrankerConnectorBuilder.connector()\n    .withRegistrationEventListener(new RegistrationEventListener() {\n        @Override\n        public void beforeRegisterToRouter(RouterRegistrationContext context) {\n            context.getWebsocketBuilder().header(\"authHeader\", \"authToken\");\n        }\n    })\n```\n\nSSL Configuration\n-----------------\n\nThis library establishes connections to one or more routers, and one local target HTTP server. These connections can\nuse HTTPS/WSS or plain HTTP/WS. If using a secure connection, then the default JDK parameters are used. However, if\nself-signed certs are used (which is common for localhost communications), you can specify a client that trusts\nall SSL certs on the `CrankerConnectorBuilder`.\n\nNote that if you need to disable hostname verification (e.g., when connecting to routers via IP addresses), we provide a handy helper `CrankerConnectorBuilder.createHttpClient(true).build()` to create a JDK HTTP client instance that trusts all certificates and disables hostname verification.\n\nThe following shows a full example:\n\n````java\npublic static void main(String[] args) {\n\n    URI targetServiceUri = startedWebServerUri();\n    \n    CrankerConnector connector = CrankerConnectorBuilder.connector()\n        .withHttpClient(CrankerConnectorBuilder.createHttpClient(true).build())\n        .withRouterLookupByDNS(URI.create(\"wss://my-router.example.org:8008\"))\n        .withRoute(\"path-prefix\")\n        .withTarget(targetServiceUri)\n        .start();\n}\n````\n\nZero downtime deployments\n-------------------------\n\nAs long as you have at least 2 instances of your connected service, you can perform a zero downtime\ndeployment by simply stopping and restarting one instance at a time. In order to ensure that any\nin-flight requests complete before your application is shutdown, call `stop(long timeout, TimeUnit timeUnit)`\non the connector object. This will deregister connector from router and wait for the active request completed.\n\n* It will return true if all active requests have completed within timeout.\n* If it returns false on timeout, requests will still be in progress. In order to stop the active requests\n  you can simply shut down your web service.\n\nHere is an example\n```java\nRuntime.getRuntime().addShutdownHook(new Thread(() -\u003e {\n    if (!connector.stop(10, TimeUnit.SECONDS)) log.info(\"Killing active requests\");\n    targetServer.stop();\n}));\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhsbc%2Fcranker-connector","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhsbc%2Fcranker-connector","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhsbc%2Fcranker-connector/lists"}