All Projects → reactive-commons → reactive-commons-java

reactive-commons / reactive-commons-java

Licence: MIT license
Common abstractions for reactive microservices

Programming Languages

java
68154 projects - #9 most used programming language

Projects that are alternatives of or similar to reactive-commons-java

KotlinReactiveMS
An educational project to learn reactive programming with Spring 5 and Kotlin
Stars: ✭ 33 (+83.33%)
Mutual labels:  reactor, reactive-microservices
reactor-workshop
Spring Reactor hands-on training (3 days)
Stars: ✭ 114 (+533.33%)
Mutual labels:  reactor
Jetlinks Community
JetLinks 基于Java8,Spring Boot 2.x ,WebFlux,Netty,Vert.x,Reactor等开发, 是一个全响应式的企业级物联网平台。支持统一物模型管理,多种设备,多种厂家,统一管理。统一设备连接管理,多协议适配(TCP,MQTT,UDP,CoAP,HTTP等),屏蔽网络编程复杂性,灵活接入不同厂家不同协议等设备。实时数据处理,设备告警,消息通知,数据转发。地理位置,数据可视化等。能帮助你快速建立物联网相关业务系统。
Stars: ✭ 2,405 (+13261.11%)
Mutual labels:  reactor
cards-hub-evolution
No description or website provided.
Stars: ✭ 68 (+277.78%)
Mutual labels:  reactor
Dtcraft
A High-performance Cluster Computing Engine
Stars: ✭ 122 (+577.78%)
Mutual labels:  reactor
Reactor-and-Turbine-control-program
This is my Reactor- and Turbine control program for ComputerCraft and BigReactors
Stars: ✭ 18 (+0%)
Mutual labels:  reactor
Spring Boot Logging
A library for logging HTTP request/response for Spring Boot application and integration with Elastic Stack
Stars: ✭ 92 (+411.11%)
Mutual labels:  reactor
paramak
Create parametric 3D fusion reactor CAD and neutronics models
Stars: ✭ 40 (+122.22%)
Mutual labels:  reactor
reactive-streams-in-java
Code for "Reactive Streams in Java" book
Stars: ✭ 19 (+5.56%)
Mutual labels:  reactor
Reactor Addons
Official modules for the Reactor project
Stars: ✭ 175 (+872.22%)
Mutual labels:  reactor
Eomaia
一个基于reactor模式的Linux/C++网络库,支持one loop per thread机制。
Stars: ✭ 159 (+783.33%)
Mutual labels:  reactor
Feign Reactive
Reactive Feign client based on Spring WebFlux
Stars: ✭ 131 (+627.78%)
Mutual labels:  reactor
Spring5Tutorial
Spring 文件的範例資源
Stars: ✭ 36 (+100%)
Mutual labels:  reactor
Spring Webflux Reactive Rest Api Demo
Build Reactive Rest APIs with Spring WebFlux and Reactive Mongo
Stars: ✭ 117 (+550%)
Mutual labels:  reactor
spring-webflux-research
spring webflux research
Stars: ✭ 42 (+133.33%)
Mutual labels:  reactor
Reactor Netty
TCP/HTTP/UDP/QUIC client/server with Reactor over Netty
Stars: ✭ 1,743 (+9583.33%)
Mutual labels:  reactor
Reactive Ms Example
An educational project to learn reactive programming with Spring 5
Stars: ✭ 157 (+772.22%)
Mutual labels:  reactor
Among-Us-Love-Couple-Mod
Among Us Love Couple Mod
Stars: ✭ 45 (+150%)
Mutual labels:  reactor
ever
Callback-less event reactor for Ruby
Stars: ✭ 79 (+338.89%)
Mutual labels:  reactor
asyncio
A C++ implementation of an industrial-grade high-performance asynchronous network library, based on asio, similar to Python's asyncio, designed for stateful services, and can be used to quickly build a variety of online game servers, microservices and pressure testing tools
Stars: ✭ 48 (+166.67%)
Mutual labels:  reactor

Reactor RabbitMQ

reactive-commons-java

The purpose of reactive-commons is to provide a set of abstractions and implementations over different patterns and practices that make the foundation of a reactive microservices architecture.

Docs: https://reactivecommons.org/reactive-commons-java/

Other projects: https://github.com/bancolombia

Sponsor by: https://medium.com/bancolombia-tech

Even though the main purpose is to provide such abstractions in a mostly generic way such abstractions would be of little use without a concrete implementation so we provide some implementations in a best effors maner that aim to be easy to change, personalize and extend.

The first approach to this work was to release a very simple abstractions and a corresponding implementation over asyncronous message driven communication between microservices build on top of project-reactor and spring boot.

Get Started

To include all (API and implementation) (Spring boot Starter):

    dependencies {
      compile 'org.reactivecommons:async-commons-rabbit-starter:<version-here>'
    }

    //IMPORTANT! if you use the version 0.6.x
    repositories {
	    ...
	    maven { url "https://repo.spring.io/milestone" }
    }
    configurations.all {
        resolutionStrategy.eachDependency {DependencyResolveDetails details ->
            if (details.requested.group == 'io.projectreactor.rabbitmq'){
                details.useVersion('1.5.0')
                details.because('Upgrade')
            }
        }
    }

In application.properties

spring.application.name=MyAppName

Or yaml

spring:
  application:
    name: myAppName

To include only domain events API:

    dependencies {
      compile 'org.reactivecommons:domain-events-api:<version-here>'
    }

To include only async commons API:

    dependencies {
      compile 'org.reactivecommons:async-commons-api:<version-here>'
    }

Main abstractions

Domain events API (Broadcast of events)

package org.reactivecommons.api.domain;
import org.reactivestreams.Publisher;

public interface DomainEventBus {
    <T> Publisher<Void> emit(DomainEvent<T> event);
}

The above interface is the main interface for Broadcast of domain events, the DomainEvent class has the following structure:

package org.reactivecommons.api.domain;

public class DomainEvent<T> {
    private final String name;
    private final String eventId;
    private final T data;

    public DomainEvent(String name, String eventId, T data) {
        this.name = name;
        this.eventId = eventId;
        this.data = data;
    }

    //... getters, equals, hascode, toString impl..

}

Usage example:

public class ManageTasksUseCase {

    private TaskToDoRepository tasks;
    private DomainEventBus eventBus;

    public Mono<TaskToDo> createNew(String name, String description) {
        return uuid()
            .flatMap(id -> TaskToDoFactory.createTask(id, name, description))
            .flatMap(tasks::save)
            .flatMap(task -> emitCreatedEvent(task).thenReturn(task));
    }

    private Mono<Void> emitCreatedEvent(TaskToDo task) {
        return Mono.from(eventBus.emit(new DomainEvent<>("task.created", task.getId(), task)));
    }
    //...
}

Then enable this feature in a Configuration class and inject implementation:

import org.reactivecommons.async.impl.config.annotations.EnableDomainEventBus;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@EnableDomainEventBus
public class MainApplication {
    public static void main(String[] args) {
        SpringApplication.run(MainApplication.class, args);
    }
    
    @Bean
    public ManageTasksUseCase manageTasksUseCase(TaskToDoRepository tasks, DomainEventBus eventBus) {
        return new ManageTasksUseCase(tasks, eventBus);
    }    
    
}

Don't forget to add the starter bundle to the main spring boot module (application):

    dependencies {
      compile 'org.reactivecommons:async-commons-rabbit-starter:<version-here>'
    }

Or add the implementation dependency if for any reason you don't want to use the starter:

    dependencies {
      compile 'org.reactivecommons:async-commons:<version-here>'
    }

Domain Event-Listener

Reactive commons has four types of listeners implemented, available to be registered in the application via the HandlerRegistry, each of them is designed to tackle
common requirements for listeners in event based applications and abstracts the behavior of event flow in every situation (Varying for example in retrying strategy, dead letter events, sources and so on).

The available event listeners are:

  • Domain Event Listener
  • Query Event Listener
  • Command Listener
  • Notification Listener

Example Code:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.beans.factory.annotation.Autowired;

@Configuration
public class SomeConfigurationClass {

    @Autowired
    private ManageTasksUseCase someBusinessDependency;

    @Bean
    public HandlerRegistry notificationEvents() {
        return HandlerRegistry.register()
            .listenNotificationEvent("some.event.name", event -> someBusinessDependency.someFunctionReturningMonoVoid(event), SomeClass.class)
            .listenEvent("some.event.name2", event -> someBusinessDependency.functionReturningMonoVoid(event), Some.class)    
            .serveQuery("query.name", query -> someBusinessDependency.findSomething(query), SomeQuery.class)    
            .handleCommand("command.name", cmd -> someBusinessDependency.handleCommand(cmd), CmdClass.class);    
    }
}

The first line below "HandlerRegistry.register()" shows how to handle a notification event (Notification event: an event that should be handled by every running instance of a microservice, e.g: notify to every instance that a configuration setting has changed and has to do a hot reload from a persistent source of that data).

The line ".listenEvent.." shows how to handle a standard event, and event that should be handled only once by some running instance of the microservice.

The line ".serveQuery..." shows how to handle a standard request/reply or rpc messages flow.

The line ".handleCommand..." shows how to handle a standard directed command, a message with a delivery guarantee.

Request-Reply

Example Code:

    public Mono<AggregateResponse> queryInformation() {
        AsyncQuery<String> userQuery = new AsyncQuery<>("user.byId", "42");
        AsyncQuery<String> projectQuery = new AsyncQuery<>("project.byId", "343");
        AsyncQuery<String> productQuery = new AsyncQuery<>("product.byId", "22");

        Mono<User> user = gateway.requestReply(userQuery, "Users", User.class);
        Mono<Project> project = gateway.requestReply(projectQuery, "Projects", Project.class);
        Mono<Product> product = gateway.requestReply(productQuery, "Products", Product.class);

        return zip(user, project, product).map(function(this::aggregate));
    }

Direct Commands

    package org.reactivecommons.async.api;

    import org.reactivecommons.api.domain.Command;
    import reactor.core.publisher.Mono;

    public interface DirectAsyncGateway {
        <T> Mono<Void> sendCommand(Command<T> command, String targetName);
        <T, R> Mono<R> requestReply(AsyncQuery<T> query, String targetName, Class<R> type);
    }

Command Type

    package org.reactivecommons.api.domain;

    public class Command<T> {
        private final String name;
        private final String commandId;
        private final T data;
    }

Send Commands

    private static final String REGISTER_MEMBER = "Members.registerMember";
    private static final String TARGET = "Members";
    private DirectAsyncGateway asyncGateway;
    
    public Mono<Void> registerMember(Member member){
        String uuid = UUID.randomUUID().toString();
        return asyncGateway.sendCommand(new Command<>(REGISTER_MEMBER, uuid, member), TARGET);
    }

Handle Commands

    private static final String REGISTER_MEMBER = "Members.registerMember";

    @Bean
    public HandlerRegistry commandHandlers(MembersRegistryUseCase useCase) {
        return HandlerRegistry.register()
            .handleCommand(REGISTER_MEMBER, useCase::registerMember, Member.class);
    }

Broker Configuration (RabbitMQ)

spring.rabbitmq.host= 8.8.8.1
spring.rabbitmq.port=5729
spring.rabbitmq.username=user
spring.rabbitmq.password=pass

Retry Strategy Config (RabbitMQ)

app.async.withDLQRetry=true
app.async.retryDelay=1000
app.async.maxRetries=10

Domain custom Configuration (RabbitMQ)

app.async.domain.events.exchange=exchangeCustomName
app.async.domain.events.maxLengthBytes=125000000

Direct custom Configuration (RabbitMQ)

app.async.direct.exchange=exchangeCustomName
app.async.direct.maxLengthBytes=125000000

Global custom Configuration (RabbitMQ)

app.async.global.exchange=exchangeCustomName
app.async.global.maxLengthBytes=125000000
app.async.maxConcurrency=20
  • withDLQRetry: Whether to enable or not the new Retry DLQ Strategy
  • retryDelay: Delay retry value in ms
  • maxRetries: Number of retries in case of error in addition to the one automatic retry per queue.
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].