{"id":15654109,"url":"https://github.com/jklingsporn/coronamq","last_synced_at":"2026-03-12T09:46:53.243Z","repository":{"id":38344953,"uuid":"253531751","full_name":"jklingsporn/coronamq","owner":"jklingsporn","description":"The simplest way to implement a task queue with Java, Vertx and PostgreSQL.","archived":false,"fork":false,"pushed_at":"2024-02-21T00:11:44.000Z","size":396,"stargazers_count":31,"open_issues_count":9,"forks_count":3,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-04-30T22:45:29.678Z","etag":null,"topics":["java","message-queue","postgres","postgresql","vertx"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jklingsporn.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}},"created_at":"2020-04-06T15:02:18.000Z","updated_at":"2024-12-16T16:05:34.000Z","dependencies_parsed_at":"2024-10-23T03:47:06.790Z","dependency_job_id":null,"html_url":"https://github.com/jklingsporn/coronamq","commit_stats":{"total_commits":37,"total_committers":2,"mean_commits":18.5,"dds":"0.027027027027026973","last_synced_commit":"c58a49668870c12d6036119e6ebe5bc9648bf975"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jklingsporn%2Fcoronamq","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jklingsporn%2Fcoronamq/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jklingsporn%2Fcoronamq/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jklingsporn%2Fcoronamq/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jklingsporn","download_url":"https://codeload.github.com/jklingsporn/coronamq/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251795391,"owners_count":21645019,"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":["java","message-queue","postgres","postgresql","vertx"],"created_at":"2024-10-03T12:49:35.402Z","updated_at":"2026-03-12T09:46:48.188Z","avatar_url":"https://github.com/jklingsporn.png","language":"Java","funding_links":[],"categories":["消息中间件"],"sub_categories":["微服务框架"],"readme":"\u003eThe simplest way to implement a task queue with Java, Vertx and PostgreSQL. \n\n# Simple\nThere are only three participants in CoronaMQ you have to reason about:\n1. **Worker(s)** process tasks that are added to the queue. Workers are bound to a label which describes the unit of work.\nThere can be multiple labels (e.g. PLACE_ORDER, CHECKOUT, etc) and thus workers.\n2. The **broker** listens to inserts made to the task queue and *send*s these tasks over the EventBus. \n3. The **TaskRepository** is interacting with the queue in the database. You can deploy it together with the broker, \nbut you don't have to.\n\nThere is also the **Dispatcher**: A dispatcher can add tasks to the queue by sending a message on the EventBus. Another\nway to add tasks is by adding them directly into the [tasks-table](#initial-setup). \n\n\n![Corona MQ Overview](doc/img/CoronaMQOverview.png?raw=true \"Corona MQ Overview\")\n\n# Fast \nThanks to PostgresSQL's [NOTIFY/LISTEN](https://www.postgresql.org/docs/current/sql-notify.html) and the\n[fastest PostgresSQL driver for Java](https://github.com/eclipse-vertx/vertx-sql-client) [^1] \nout there, tasks are instantly pushed to the EventBus. There is no polling. To empty the task queue as fast as possible, \nworkers additionally request tasks when they are deployed and after they've completed a task.\n\n# Persistent \nThe tasks are stored in a PostgreSQL database guaranteeing durability and consistency. Your application might already \nuse a PostgreSQL database in the persistence layer, so you don't have to bring another player to your system architecture.\nThe fewer players, the fewer errors.  \n\n# Once\nMany queues out there guarantee `at least once`-delivery which means tasks might get handled twice. But what you really want \nis `exactly once` delivery. You have one job - and it should be done once. However, in a real world, there are network timeouts, \ndatabase errors et al. so the best you can get is `effectively once` delivery and this is what CoronaMQ aims for.\n\n# Usage \n\n## Maven\nCoronaMQ supports the following API-flavors:\n\n### vertx-Future\n```\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.github.jklingsporn\u003c/groupId\u003e\n    \u003cartifactId\u003ecoronamq-core\u003c/artifactId\u003e\n    \u003cversion\u003e0.2\u003c/version\u003e\n\u003c/dependency\u003e\n```\n### Mutiny\n```\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.github.jklingsporn\u003c/groupId\u003e\n    \u003cartifactId\u003ecoronamq-mutiny\u003c/artifactId\u003e\n    \u003cversion\u003e0.2\u003c/version\u003e\n\u003c/dependency\u003e\n```\n### rxjava3\n```\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.github.jklingsporn\u003c/groupId\u003e\n    \u003cartifactId\u003ecoronamq-rxjava\u003c/artifactId\u003e\n    \u003cversion\u003e0.2\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n## Initial setup\n- To run the examples, you need a running docker daemon.\n- For a more advanced test, you can use the provided docker file.\n- All others need to add the following SQL to their existing database:\n```\nCREATE TYPE task_status AS ENUM ('NEW', 'RUNNING','COMPLETED','FAILED');\nCREATE TABLE tasks(id UUID,label text, \tpayload JSONB, status task_status, update_time timestamp);\n\nCREATE OR REPLACE FUNCTION task_status_notify()\n\tRETURNS trigger AS\n$$\nBEGIN\n\tPERFORM pg_notify('coronamq_task_update', jsonb_build_object('id', NEW.id::text, 'payload',new.payload, 'label',new.label)::text);\n\tRETURN NEW;\nEND;\n$$ LANGUAGE plpgsql;\n\n\nCREATE TRIGGER task_status_change\n\tAFTER INSERT\n\tON tasks\n\tFOR EACH ROW\nEXECUTE PROCEDURE task_status_notify();\n``` \n\n## Code example\n\nThe following example uses the `Future`-API\n```\n@Test\npublic void boostrapExample(Vertx vertx, VertxTestContext testContext){\n    //configurable options\n    CoronaMqOptions coronaMqOptions = new CoronaMqOptions();\n    \n    //a simple worker that just completes any task it receives\n    SimpleWorker worker = new SimpleWorker(vertx, coronaMqOptions);\n    \n    //an example configuration with a broker, repository and worker\n    Future\u003cBootstrapSpreadStep\u003e spread = CoronaMq.create(vertx,coronaMqOptions)\n            .withBroker()\n            .withRepository()\n            .withWorker(worker)\n            .spread(); //spread the wor(l)d\n            \n    testContext\n            .assertComplete(spread)\n            //send a new task with \"test\"-label to the queue\n            .compose(s-\u003e s.dispatch(\"test\",new JsonObject().put(\"someValue\",\"hi\")))\n            .onComplete(testContext.succeeding(UUID::fromString))\n            //complete the work\n            .compose(v-\u003e worker.getCurrentWork())\n            //shut down all components\n            .compose(v-\u003espread.compose(BootstrapSpreadStep::vaccinate))\n            .onComplete(testContext.succeedingThenComplete())\n    ;\n}\n```\nMore examples can be found in the [examples-module](/coronamq-examples).\n\n# Awesome\nThis project is a showcase for various cool features that go beyond a simple \"Hello world\"-example:\n- [Vertx Service Discovery](https://vertx.io/docs/vertx-service-discovery/java/) to detect the repository's availability\n- [Vertx Service Proxies](https://vertx.io/docs/vertx-service-proxy/java/) to remotely interoperate with the repository using\nit's interface\n- [Vertx Codegen](https://github.com/vert-x3/vertx-codegen) to generate [Mutiny](https://smallrye.io/smallrye-mutiny/)-\n  and [RxJava](https://github.com/ReactiveX/RxJava)-APIs\n- [Testcontainers](https://www.testcontainers.org/) for running the integration tests\n- [Micrometer Metrics](https://vertx.io/docs/vertx-micrometer-metrics/java/) to see what's going on \n\n# Community has spoken\nI originally created the project under the name PoXMQ (**Po**stgres Vert**X** **MQ**) but wasn't\ncompletely satisfied with it. So I made a poll on [twitter](https://twitter.com/klingspoon/status/1245657559484076034) - what could possibly go wrong?\n![Never feed the trolls](doc/img/NeverFeedTheTrolls.png?raw=true \"never feed the trolls\")\n\n# Footnotes :mask:\n[^1]: https://www.techempower.com/benchmarks/#section=data-r15\u0026hw=ph\u0026test=db","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjklingsporn%2Fcoronamq","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjklingsporn%2Fcoronamq","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjklingsporn%2Fcoronamq/lists"}