{"id":36415724,"url":"https://github.com/atleon/atleon","last_synced_at":"2026-04-18T21:08:49.693Z","repository":{"id":41952369,"uuid":"399619534","full_name":"atleon/atleon","owner":"atleon","description":"Lightweight infinite reactive stream processing framework","archived":false,"fork":false,"pushed_at":"2026-04-02T16:52:36.000Z","size":3249,"stargazers_count":36,"open_issues_count":0,"forks_count":6,"subscribers_count":3,"default_branch":"main","last_synced_at":"2026-04-03T01:10:50.733Z","etag":null,"topics":["java","kafka","rabbitmq","reactive-streams","reactor","sns","sns-client","sqs","sqs-client"],"latest_commit_sha":null,"homepage":"http://atleon.io","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/atleon.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","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":"2021-08-24T22:21:50.000Z","updated_at":"2026-04-02T16:52:39.000Z","dependencies_parsed_at":"2023-10-01T20:48:44.846Z","dependency_job_id":"a1c88837-a38b-4584-88f8-213d66944714","html_url":"https://github.com/atleon/atleon","commit_stats":null,"previous_names":[],"tags_count":110,"template":false,"template_full_name":null,"purl":"pkg:github/atleon/atleon","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/atleon%2Fatleon","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/atleon%2Fatleon/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/atleon%2Fatleon/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/atleon%2Fatleon/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/atleon","download_url":"https://codeload.github.com/atleon/atleon/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/atleon%2Fatleon/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31982756,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-18T17:30:12.329Z","status":"ssl_error","status_checked_at":"2026-04-18T17:29:59.069Z","response_time":103,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["java","kafka","rabbitmq","reactive-streams","reactor","sns","sns-client","sqs","sqs-client"],"created_at":"2026-01-11T16:58:20.964Z","updated_at":"2026-04-18T21:08:49.670Z","avatar_url":"https://github.com/atleon.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Atleon\n\n[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)\n[![Main Build Workflow](https://github.com/atleon/atleon/actions/workflows/main.yml/badge.svg?branch=main)](https://github.com/atleon/atleon/actions/workflows/main.yml)\n[![Maven Central](https://img.shields.io/maven-central/v/io.atleon/atleon-core)](https://search.maven.org/artifact/io.atleon/atleon-core)\n[![Javadoc](https://javadoc.io/badge2/io.atleon/atleon-core/javadoc.svg)](https://javadoc.io/doc/io.atleon/atleon-core)\n\nAtleon is a lightweight reactive stream processing framework that scalably transforms data from any supported infrastructure, and allows sending that data nearly anywhere, while _seamlessly_ maintaining **at** **le**ast **on**ce processing guarantees.\n\nAtleon is based on [Reactive Streams](https://www.reactive-streams.org/) and backed by [Project Reactor](https://projectreactor.io/). There are two levels of client APIs offered:\n\n- **Low-Level**: Low-level client APIs are thin reactive wrappers around third-party native infrastructure clients. These APIs are defined in terms of Reactor-native types (e.g. [`Flux`](https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Flux.html) and [`Mono`](https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Mono.html)), and emit elements that contain (or otherwise reference) native infrastructure types. Consumption of messages is facilitated via `Receiver` implementations, with emitted elements containing callbacks for acknowledgement (both positive/successful and negative/failed). Production of messages is facilitated via `Sender` implementations, with emitted elements (implementations of [`SenderResult`](../../blob/main/base/core/src/main/java/io/atleon/core/SenderResult.java)) containing metadata about successes or errors indicating production failure.\n- **High-Level**: High-level client APIs decorate low-level clients with an Atleon-native abstraction called [`Alo`](../../blob/main/base/core/src/main/java/io/atleon/core/Alo.java) (short for At Least Once). `Alo` facilitates per-element context which (at minimum) provides access to acknowledgement, and allows for decorating its context with functionality like metrics, distributed tracing, and application-specific metadata. In order to simplify building streams that emit/consume `Alo\u003cT\u003e`, high-level clients produce a special [`AloFlux\u003cT\u003e`](../../blob/main/base/core/src/main/java/io/atleon/core/AloFlux.java) type that bridges operations to an underlying `Flux\u003cAlo\u003cT\u003e\u003e`, and allows for defining reactive pipelines purely in terms of data typing (`T`), while providing automatic context propagation.\n\n## Documentation and Getting Started\n\nAtleon documentation and instructions on how to get started are available in the [Wiki](../../wiki).\n\n### Low-Level Client Example\n\nThe following is an example of using low-level clients in Atleon:\n\n```java\nimport io.atleon.kafka.KafkaReceiver;\nimport io.atleon.kafka.KafkaReceiverOptions;\nimport io.atleon.kafka.KafkaReceiverRecord;\nimport io.atleon.kafka.KafkaSender;\nimport io.atleon.kafka.KafkaSenderOptions;\nimport io.atleon.kafka.KafkaSenderRecord;\nimport org.apache.kafka.clients.CommonClientConfigs;\nimport org.apache.kafka.clients.consumer.ConsumerConfig;\nimport org.apache.kafka.clients.producer.ProducerConfig;\nimport org.apache.kafka.common.serialization.StringDeserializer;\nimport org.apache.kafka.common.serialization.StringSerializer;\nimport reactor.core.Disposable;\nimport reactor.core.publisher.Flux;\n\nimport java.time.Duration;\nimport java.util.Collections;\n\npublic class Example {\n\n    public static void main(String[] args) throws Exception {\n        KafkaSenderOptions\u003cString, String\u003e senderOptions = KafkaSenderOptions.\u003cString, String\u003enewBuilder()\n            .producerProperty(CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG, \"localhost:9092\")\n            .producerProperty(CommonClientConfigs.CLIENT_ID_CONFIG, \"example\")\n            .producerProperty(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName())\n            .producerProperty(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName())\n            .build();\n        \n        KafkaReceiverOptions\u003cString, String\u003e receiverOptions = KafkaReceiverOptions.\u003cString, String\u003enewBuilder()\n            .consumerProperty(CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG, \"localhost:9092\")\n            .consumerProperty(CommonClientConfigs.CLIENT_ID_CONFIG, \"example\")\n            .consumerProperty(ConsumerConfig.GROUP_ID_CONFIG, \"consumer-group-id\")\n            .consumerProperty(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName())\n            .consumerProperty(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName())\n            .build();\n\n        // Periodically produce records\n        KafkaSender\u003cString, String\u003e sender = KafkaSender.create(senderOptions);\n        Disposable production = Flux.interval(Duration.ofMillis(100))\n            .map(it -\u003e KafkaSenderRecord.create(\"source-topic\", it.toString(), it.toString(), it))\n            .transform(sender::send)\n            .doFinally(__ -\u003e sender.close())\n            .subscribe();\n\n        // Consume produced records\n        Disposable consumption = KafkaReceiver.create(receiverOptions)\n            .receiveManual(Collections.singletonList(\"source-topic\"))\n            .doOnNext(it -\u003e System.out.printf(\"Consumed record with key=%s and value=%s\", it.key(), it.value()))\n            .subscribe(KafkaReceiverRecord::acknowledge);\n\n        System.in.read(); // Added for posterity - Everything above will execute asynchronously\n        production.dispose(); // Stop producing\n        consumption.dispose(); // Stop consuming\n    }\n}\n```\n\n### High-Level AloStream Example\n\nThe next example builds on the availability of low-level clients by switching to high-level `Alo` clients, removing manual production of data in favor of demonstrating sending/producing transformed messages, and wrapping the resulting stream definition in an implementation of `AloStream`:\n\n```java\nimport io.atleon.core.SelfConfigurableAloStream;\nimport io.atleon.core.DefaultAloSenderResultSubscriber;\nimport io.atleon.kafka.AloKafkaReceiver;\nimport io.atleon.kafka.AloKafkaSender;\nimport io.atleon.kafka.KafkaConfigSource;\nimport org.apache.kafka.common.serialization.StringDeserializer;\nimport org.apache.kafka.common.serialization.StringSerializer;\nimport reactor.core.Disposable;\n\npublic class MyStream extends SelfConfigurableAloStream {\n\n    private final KafkaConfigSource configSource;\n\n    private final String sourceTopic;\n\n    private final String destinationTopic;\n\n    public MyStream(KafkaConfigSource configSource, String sourceTopic, String destinationTopic) {\n        this.configSource = configSource;\n        this.sourceTopic = sourceTopic;\n        this.destinationTopic = destinationTopic;\n    }\n\n    @Override\n    public Disposable startDisposable() {\n        AloKafkaSender\u003cString, String\u003e sender = buildKafkaSender();\n\n        return buildKafkaReceiver()\n            .receiveAloRecords(sourceTopic)\n            .mapNotNull(it -\u003e it.value() != null ? it.value().toUpperCase() : null) // Business logic goes here\n            .transform(sender.sendAloValues(destinationTopic, message -\u003e message.substring(0, 1)))\n            .resubscribeOnError(name())\n            .doFinally(sender::close)\n            .subscribeWith(new DefaultAloSenderResultSubscriber\u003c\u003e());\n    }\n\n    private AloKafkaSender\u003cString, String\u003e buildKafkaSender() {\n        return configSource\n            .withClientId(name())\n            .withKeySerializer(StringSerializer.class)\n            .withValueSerializer(StringSerializer.class)\n            .as(AloKafkaSender::create);\n    }\n\n    private AloKafkaReceiver\u003cString, String\u003e buildKafkaReceiver() {\n        return configSource\n            .withClientId(name())\n            .withConsumerGroupId(\"consumer-group-id\")\n            .withKeyDeserializer(StringSerializer.class)\n            .withValueDeserializer(StringSerializer.class)\n            .as(AloKafkaReceiver::create);\n    }\n}\n\n```\n\n### Spring AloStream Example\n\nAtleon has built-in integration with Spring, where a fully configured `AloStream` looks like the following:\n\n`pom.xml`:\n\n```xml\n\n\u003cdependencies\u003e\n    \u003cdependency\u003e\n        \u003cgroupId\u003eio.atleon\u003c/groupId\u003e\n        \u003cartifactId\u003eatleon-kafka\u003c/artifactId\u003e \u003c!-- Include infrastructure client(s) --\u003e\n        \u003cversion\u003e${atleon.version}\u003c/version\u003e\n    \u003c/dependency\u003e\n    \u003cdependency\u003e\n        \u003cgroupId\u003eio.atleon\u003c/groupId\u003e\n        \u003cartifactId\u003eatleon-spring\u003c/artifactId\u003e \u003c!-- Application binding(s) --\u003e\n        \u003cversion\u003e${atleon.version}\u003c/version\u003e\n    \u003c/dependency\u003e\n\u003c/dependencies\u003e\n```\n\n`application.yml`:\n\n```yaml\natleon:\n  config.sources:\n    - name: kafkaConfigSource\n      type: kafka\n      bootstrap.servers: localhost:9092\n\nstream:\n  kafka:\n    destination.topic: output\n    source.topic: input\n```\n\n`MyStream.java`:\n\n```java\nimport io.atleon.core.DefaultAloSenderResultSubscriber;\nimport io.atleon.kafka.AloKafkaReceiver;\nimport io.atleon.kafka.AloKafkaSender;\nimport io.atleon.kafka.KafkaConfigSource;\nimport io.atleon.spring.AutoConfigureStream;\nimport io.atleon.spring.SpringAloStream;\nimport org.apache.kafka.common.serialization.StringDeserializer;\nimport org.apache.kafka.common.serialization.StringSerializer;\nimport org.springframework.context.ApplicationContext;\nimport reactor.core.Disposable;\n\n@AutoConfigureStream\npublic class MyStream extends SpringAloStream {\n\n    private final KafkaConfigSource configSource;\n\n    public MyStream(ApplicationContext context) {\n        super(context);\n        this.configSource = context.getBean(\"kafkaConfigSource\", KafkaConfigSource.class);\n    }\n\n    @Override\n    public Disposable startDisposable(MyStreamConfig config) {\n        AloKafkaSender\u003cString, String\u003e sender = buildKafkaSender();\n        String destinationTopic = getRequiredProperty(\"stream.kafka.destination.topic\");\n\n        return buildKafkaReceiver()\n            .receiveAloRecords(getRequiredProperty(\"stream.kafka.source.topic\"))\n            .mapNotNull(it -\u003e it.value() != null ? it.value().toUpperCase() : null) // Business logic goes here\n            .transform(sender.sendAloValues(destinationTopic, message -\u003e message.substring(0, 1)))\n            .resubscribeOnError(name())\n            .doFinally(sender::close)\n            .subscribeWith(new DefaultAloSenderResultSubscriber\u003c\u003e());\n    }\n\n    private AloKafkaSender\u003cString, String\u003e buildKafkaSender() {\n        return configSource\n            .withClientId(name())\n            .withKeySerializer(StringSerializer.class)\n            .withValueSerializer(StringSerializer.class)\n            .as(AloKafkaSender::create);\n    }\n\n    private AloKafkaReceiver\u003cString, String\u003e buildKafkaReceiver() {\n        return configSource\n            .withClientId(name())\n            .withConsumerGroupId(\"consumer-group-id\")\n            .withKeyDeserializer(StringDeserializer.class)\n            .withValueDeserializer(StringDeserializer.class)\n            .as(AloKafkaReceiver::create);\n    }\n}\n```\n\n### Runnable Examples\n\nThe [examples module](examples) contains runnable classes showing Atleon in action and intended usage.\n\n## Building\n\nAtleon is built using Maven. Installing Maven locally is optional as you can use the Maven Wrapper:\n\n```$bash\n./mvnw clean verify\n```\n\n#### Docker\n\nAtleon makes use of [Testcontainers](https://www.testcontainers.org/) for some unit tests. Testcontainers is based on Docker, so successfully building Atleon requires Docker to be running locally.\n\n## Contributing\n\nPlease refer to [CONTRIBUTING](CONTRIBUTING.md) for information on how to contribute to Atleon\n\n## Legal\n\nThis project is available under the [Apache 2.0 License](http://www.apache.org/licenses/LICENSE-2.0.html).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fatleon%2Fatleon","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fatleon%2Fatleon","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fatleon%2Fatleon/lists"}