├── config-server ├── src │ └── main │ │ ├── resources │ │ └── bootstrap.yml │ │ └── java │ │ └── pl │ │ └── piomin │ │ └── service │ │ └── config │ │ └── ConfigApplication.java └── pom.xml ├── trip-management ├── src │ ├── main │ │ ├── resources │ │ │ └── application.yml │ │ └── java │ │ │ └── pl │ │ │ └── piomin │ │ │ └── services │ │ │ └── trip │ │ │ ├── model │ │ │ ├── TripStatus.java │ │ │ └── Trip.java │ │ │ ├── repository │ │ │ └── TripRepository.java │ │ │ ├── TripApplication.java │ │ │ ├── publish │ │ │ └── TripPublisher.java │ │ │ ├── TripConfiguration.java │ │ │ └── web │ │ │ └── TripController.java │ └── test │ │ └── java │ │ └── pl │ │ └── piomin │ │ └── services │ │ └── trip │ │ ├── TripTestListener.java │ │ └── TripControllerIntegrationTests.java └── pom.xml ├── driver-management ├── src │ ├── main │ │ ├── resources │ │ │ └── application.yml │ │ └── java │ │ │ └── pl │ │ │ └── piomin │ │ │ └── services │ │ │ └── driver │ │ │ ├── model │ │ │ ├── DriverStatus.java │ │ │ ├── TripStatus.java │ │ │ ├── Driver.java │ │ │ └── Trip.java │ │ │ ├── repository │ │ │ └── DriverRepository.java │ │ │ ├── DriverApplication.java │ │ │ ├── web │ │ │ └── DriverController.java │ │ │ ├── DriverConfiguration.java │ │ │ └── subscribe │ │ │ └── DriverSubscriber.java │ └── test │ │ └── java │ │ └── pl │ │ └── piomin │ │ └── services │ │ └── driver │ │ └── DriverRepositoryIntegrationTests.java └── pom.xml ├── passenger-management ├── src │ └── main │ │ ├── resources │ │ └── application.yml │ │ └── java │ │ └── pl │ │ └── piomin │ │ └── services │ │ └── passenger │ │ ├── model │ │ ├── TripStatus.java │ │ ├── Passenger.java │ │ └── Trip.java │ │ ├── repository │ │ └── PassengerRepository.java │ │ ├── PassengerApplication.java │ │ ├── web │ │ └── PassengerController.java │ │ ├── PassengerConfiguration.java │ │ └── subscribe │ │ └── PassengerSubscriber.java └── pom.xml ├── renovate.json ├── README.md ├── .circleci └── config.yml └── pom.xml /config-server/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: config-server 4 | profiles: 5 | active: redis 6 | server: 7 | port: 8888 -------------------------------------------------------------------------------- /trip-management/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: trip-management 4 | config: 5 | import: "optional:configserver:http://localhost:8888" -------------------------------------------------------------------------------- /driver-management/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: driver-management 4 | config: 5 | import: "optional:configserver:http://localhost:8888" -------------------------------------------------------------------------------- /passenger-management/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: passenger-management 4 | config: 5 | import: "optional:configserver:http://localhost:8888" -------------------------------------------------------------------------------- /driver-management/src/main/java/pl/piomin/services/driver/model/DriverStatus.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.services.driver.model; 2 | 3 | public enum DriverStatus { 4 | 5 | WAITING, BUSY; 6 | 7 | } 8 | -------------------------------------------------------------------------------- /trip-management/src/main/java/pl/piomin/services/trip/model/TripStatus.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.services.trip.model; 2 | 3 | public enum TripStatus { 4 | 5 | NEW, IN_PROGRESS, DONE; 6 | 7 | } 8 | -------------------------------------------------------------------------------- /driver-management/src/main/java/pl/piomin/services/driver/model/TripStatus.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.services.driver.model; 2 | 3 | public enum TripStatus { 4 | 5 | NEW, IN_PROGRESS, DONE; 6 | 7 | } 8 | -------------------------------------------------------------------------------- /passenger-management/src/main/java/pl/piomin/services/passenger/model/TripStatus.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.services.passenger.model; 2 | 3 | public enum TripStatus { 4 | 5 | NEW, IN_PROGRESS, DONE; 6 | 7 | } 8 | -------------------------------------------------------------------------------- /trip-management/src/main/java/pl/piomin/services/trip/repository/TripRepository.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.services.trip.repository; 2 | 3 | import pl.piomin.services.trip.model.Trip; 4 | 5 | import org.springframework.data.repository.CrudRepository; 6 | 7 | public interface TripRepository extends CrudRepository { 8 | } 9 | -------------------------------------------------------------------------------- /driver-management/src/main/java/pl/piomin/services/driver/repository/DriverRepository.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.services.driver.repository; 2 | 3 | import pl.piomin.services.driver.model.Driver; 4 | 5 | import org.springframework.data.repository.CrudRepository; 6 | 7 | public interface DriverRepository extends CrudRepository { 8 | } 9 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:base",":dependencyDashboard" 5 | ], 6 | "packageRules": [ 7 | { 8 | "matchUpdateTypes": ["minor", "patch", "pin", "digest"], 9 | "automerge": true 10 | } 11 | ], 12 | "prCreation": "not-pending" 13 | } -------------------------------------------------------------------------------- /passenger-management/src/main/java/pl/piomin/services/passenger/repository/PassengerRepository.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.services.passenger.repository; 2 | 3 | import pl.piomin.services.passenger.model.Passenger; 4 | 5 | import org.springframework.data.repository.CrudRepository; 6 | 7 | public interface PassengerRepository extends CrudRepository { 8 | } 9 | -------------------------------------------------------------------------------- /trip-management/src/main/java/pl/piomin/services/trip/TripApplication.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.services.trip; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class TripApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(TripApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /driver-management/src/main/java/pl/piomin/services/driver/DriverApplication.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.services.driver; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class DriverApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(DriverApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /passenger-management/src/main/java/pl/piomin/services/passenger/PassengerApplication.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.services.passenger; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class PassengerApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(PassengerApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /config-server/src/main/java/pl/piomin/service/config/ConfigApplication.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.service.config; 2 | 3 | import org.springframework.boot.autoconfigure.SpringBootApplication; 4 | import org.springframework.boot.builder.SpringApplicationBuilder; 5 | import org.springframework.cloud.config.server.EnableConfigServer; 6 | 7 | @SpringBootApplication 8 | @EnableConfigServer 9 | public class ConfigApplication { 10 | 11 | public static void main(String[] args) { 12 | new SpringApplicationBuilder(ConfigApplication.class).run(args); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /passenger-management/src/main/java/pl/piomin/services/passenger/model/Passenger.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.services.passenger.model; 2 | 3 | import org.springframework.data.annotation.Id; 4 | import org.springframework.data.geo.Point; 5 | import org.springframework.data.redis.core.RedisHash; 6 | import org.springframework.data.redis.core.index.GeoIndexed; 7 | 8 | @RedisHash("passenger") 9 | public class Passenger { 10 | 11 | @Id 12 | private Long id; 13 | private String name; 14 | @GeoIndexed 15 | private Point location; 16 | 17 | public Long getId() { 18 | return id; 19 | } 20 | 21 | public void setId(Long id) { 22 | this.id = id; 23 | } 24 | 25 | public String getName() { 26 | return name; 27 | } 28 | 29 | public void setName(String name) { 30 | this.name = name; 31 | } 32 | 33 | public Point getLocation() { 34 | return location; 35 | } 36 | 37 | public void setLocation(Point location) { 38 | this.location = location; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /config-server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | pl.piomin.services 8 | sample-redis-microservices 9 | 1.0-SNAPSHOT 10 | 11 | 1.0-SNAPSHOT 12 | config-server 13 | 14 | 15 | ${project.artifactId} 16 | 17 | 18 | 19 | 20 | org.springframework.cloud 21 | spring-cloud-config-server 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-data-redis 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Redis In Microservices Architecture [![Twitter](https://img.shields.io/twitter/follow/piotr_minkowski.svg?style=social&logo=twitter&label=Follow%20Me)](https://twitter.com/piotr_minkowski) 2 | 3 | [![CircleCI](https://circleci.com/gh/piomin/sample-redis-microservices.svg?style=svg)](https://circleci.com/gh/piomin/sample-redis-microservices) 4 | 5 | [![SonarCloud](https://sonarcloud.io/images/project_badges/sonarcloud-black.svg)](https://sonarcloud.io/dashboard?id=piomin_sample-redis-microservices) 6 | [![Bugs](https://sonarcloud.io/api/project_badges/measure?project=piomin_sample-redis-microservices&metric=bugs)](https://sonarcloud.io/dashboard?id=piomin_sample-redis-microservices) 7 | [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=piomin_sample-redis-microservices&metric=coverage)](https://sonarcloud.io/dashboard?id=piomin_sample-redis-microservices) 8 | [![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=piomin_sample-redis-microservices&metric=ncloc)](https://sonarcloud.io/dashboard?id=piomin_sample-redis-microservices) 9 | 10 | Detailed description can be found here: [Redis In Microservices Architecture](https://piotrminkowski.com/2019/03/18/redis-in-microservices-architecture/) 11 | -------------------------------------------------------------------------------- /driver-management/src/main/java/pl/piomin/services/driver/model/Driver.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.services.driver.model; 2 | 3 | import org.springframework.data.annotation.Id; 4 | import org.springframework.data.geo.Point; 5 | import org.springframework.data.redis.core.RedisHash; 6 | import org.springframework.data.redis.core.index.GeoIndexed; 7 | 8 | @RedisHash("driver") 9 | public class Driver { 10 | 11 | @Id 12 | private Long id; 13 | private String name; 14 | @GeoIndexed 15 | private Point location; 16 | private DriverStatus status; 17 | 18 | public Long getId() { 19 | return id; 20 | } 21 | 22 | public void setId(Long id) { 23 | this.id = id; 24 | } 25 | 26 | public String getName() { 27 | return name; 28 | } 29 | 30 | public void setName(String name) { 31 | this.name = name; 32 | } 33 | 34 | public Point getLocation() { 35 | return location; 36 | } 37 | 38 | public void setLocation(Point location) { 39 | this.location = location; 40 | } 41 | 42 | public DriverStatus getStatus() { 43 | return status; 44 | } 45 | 46 | public void setStatus(DriverStatus status) { 47 | this.status = status; 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /trip-management/src/main/java/pl/piomin/services/trip/publish/TripPublisher.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.services.trip.publish; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import pl.piomin.services.trip.model.Trip; 8 | 9 | import org.springframework.data.redis.core.RedisTemplate; 10 | import org.springframework.data.redis.listener.ChannelTopic; 11 | import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; 12 | 13 | public class TripPublisher { 14 | 15 | private static final Logger LOGGER = LoggerFactory.getLogger(TripPublisher.class); 16 | 17 | RedisTemplate redisTemplate; 18 | ChannelTopic topic; 19 | 20 | public TripPublisher(RedisTemplate redisTemplate, ChannelTopic topic) { 21 | this.redisTemplate = redisTemplate; 22 | this.redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer(Trip.class)); 23 | this.topic = topic; 24 | } 25 | 26 | public void publish(Trip trip) throws JsonProcessingException { 27 | LOGGER.info("Sending: {}", trip); 28 | redisTemplate.convertAndSend(topic.getTopic(), trip); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /trip-management/src/main/java/pl/piomin/services/trip/TripConfiguration.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.services.trip; 2 | 3 | import pl.piomin.services.trip.model.Trip; 4 | import pl.piomin.services.trip.publish.TripPublisher; 5 | 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | import org.springframework.data.redis.connection.RedisConnectionFactory; 10 | import org.springframework.data.redis.connection.RedisStandaloneConfiguration; 11 | import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; 12 | import org.springframework.data.redis.core.RedisTemplate; 13 | import org.springframework.data.redis.listener.ChannelTopic; 14 | import org.springframework.data.redis.repository.configuration.EnableRedisRepositories; 15 | 16 | @Configuration 17 | @EnableRedisRepositories 18 | public class TripConfiguration { 19 | 20 | @Autowired 21 | RedisTemplate redisTemplate; 22 | 23 | @Bean 24 | TripPublisher redisPublisher() { 25 | return new TripPublisher(redisTemplate, topic()); 26 | } 27 | 28 | @Bean 29 | ChannelTopic topic() { 30 | return new ChannelTopic("trips"); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /trip-management/src/test/java/pl/piomin/services/trip/TripTestListener.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.services.trip; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.data.redis.connection.Message; 7 | import org.springframework.data.redis.connection.MessageListener; 8 | import pl.piomin.services.trip.model.Trip; 9 | 10 | import java.io.IOException; 11 | import java.util.concurrent.BlockingQueue; 12 | 13 | public class TripTestListener implements MessageListener { 14 | 15 | private static final Logger LOG = LoggerFactory.getLogger(TripTestListener.class); 16 | private BlockingQueue queue; 17 | 18 | public TripTestListener(BlockingQueue queue) { 19 | this.queue = queue; 20 | } 21 | 22 | @Override 23 | public void onMessage(Message message, byte[] bytes) { 24 | ObjectMapper mapper = new ObjectMapper(); 25 | try { 26 | Trip trip = mapper.readValue(message.getBody(), Trip.class); 27 | boolean ok = queue.offer(trip); 28 | LOG.info("Received body->{}, sentToQueue->{}", trip, ok); 29 | } catch (IOException e) { 30 | throw new RuntimeException(e); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: '2.1' 2 | 3 | jobs: 4 | analyze: 5 | docker: 6 | - image: 'cimg/openjdk:21.0.9' 7 | steps: 8 | - checkout 9 | - run: 10 | name: Analyze on SonarCloud 11 | command: mvn verify sonar:sonar -DskipTests 12 | test: 13 | executor: machine_executor_amd64 14 | steps: 15 | - checkout 16 | - run: 17 | name: Install OpenJDK 21 18 | command: | 19 | java -version 20 | sudo apt-get update && sudo apt-get install openjdk-21-jdk 21 | sudo update-alternatives --set java /usr/lib/jvm/java-21-openjdk-amd64/bin/java 22 | sudo update-alternatives --set javac /usr/lib/jvm/java-21-openjdk-amd64/bin/javac 23 | java -version 24 | export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64 25 | - run: 26 | name: Maven Tests 27 | command: mvn test 28 | 29 | orbs: 30 | maven: circleci/maven@2.1.1 31 | 32 | executors: 33 | machine_executor_amd64: 34 | machine: 35 | image: ubuntu-2204:2023.10.1 36 | environment: 37 | architecture: "amd64" 38 | platform: "linux/amd64" 39 | 40 | workflows: 41 | maven_test: 42 | jobs: 43 | - test 44 | - analyze: 45 | context: SonarCloud -------------------------------------------------------------------------------- /driver-management/src/main/java/pl/piomin/services/driver/web/DriverController.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.services.driver.web; 2 | 3 | import java.util.List; 4 | import java.util.Optional; 5 | 6 | import pl.piomin.services.driver.model.Driver; 7 | import pl.piomin.services.driver.repository.DriverRepository; 8 | 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.web.bind.annotation.GetMapping; 11 | import org.springframework.web.bind.annotation.PathVariable; 12 | import org.springframework.web.bind.annotation.PostMapping; 13 | import org.springframework.web.bind.annotation.RequestMapping; 14 | import org.springframework.web.bind.annotation.RestController; 15 | 16 | @RestController 17 | @RequestMapping("/drivers") 18 | public class DriverController { 19 | 20 | @Autowired 21 | DriverRepository repository; 22 | 23 | @PostMapping 24 | public Driver add(Driver driver) { 25 | return repository.save(driver); 26 | } 27 | 28 | @GetMapping("/{id}") 29 | public Driver findById(@PathVariable("id") Long id) { 30 | Optional optDriver = repository.findById(id); 31 | if (optDriver.isPresent()) { 32 | return optDriver.get(); 33 | } else { 34 | return null; 35 | } 36 | } 37 | 38 | @GetMapping 39 | public List findAll() { 40 | return (List) repository.findAll(); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /passenger-management/src/main/java/pl/piomin/services/passenger/web/PassengerController.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.services.passenger.web; 2 | 3 | import java.util.List; 4 | import java.util.Optional; 5 | 6 | import pl.piomin.services.passenger.model.Passenger; 7 | import pl.piomin.services.passenger.repository.PassengerRepository; 8 | 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.web.bind.annotation.GetMapping; 11 | import org.springframework.web.bind.annotation.PathVariable; 12 | import org.springframework.web.bind.annotation.PostMapping; 13 | import org.springframework.web.bind.annotation.RequestMapping; 14 | import org.springframework.web.bind.annotation.RestController; 15 | 16 | @RestController 17 | @RequestMapping("/passengers") 18 | public class PassengerController { 19 | 20 | @Autowired 21 | PassengerRepository repository; 22 | 23 | @PostMapping 24 | public Passenger add(Passenger passenger) { 25 | return repository.save(passenger); 26 | } 27 | 28 | @GetMapping("/{id}") 29 | public Passenger findById(@PathVariable("id") Long id) { 30 | Optional optPassenger = repository.findById(id); 31 | if (optPassenger.isPresent()) { 32 | return optPassenger.get(); 33 | } else { 34 | return null; 35 | } 36 | } 37 | 38 | @GetMapping 39 | public List findAll() { 40 | return (List) repository.findAll(); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /driver-management/src/main/java/pl/piomin/services/driver/model/Trip.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.services.driver.model; 2 | 3 | import java.io.Serializable; 4 | import java.util.Date; 5 | 6 | public class Trip implements Serializable { 7 | 8 | private Long id; 9 | private Date startDate; 10 | private Long driverId; 11 | private Long passengerId; 12 | private TripStatus status; 13 | 14 | public Long getId() { 15 | return id; 16 | } 17 | 18 | public void setId(Long id) { 19 | this.id = id; 20 | } 21 | 22 | public Date getStartDate() { 23 | return startDate; 24 | } 25 | 26 | public void setStartDate(Date startDate) { 27 | this.startDate = startDate; 28 | } 29 | 30 | public Long getDriverId() { 31 | return driverId; 32 | } 33 | 34 | public void setDriverId(Long driverId) { 35 | this.driverId = driverId; 36 | } 37 | 38 | public Long getPassengerId() { 39 | return passengerId; 40 | } 41 | 42 | public void setPassengerId(Long passengerId) { 43 | this.passengerId = passengerId; 44 | } 45 | 46 | public TripStatus getStatus() { 47 | return status; 48 | } 49 | 50 | public void setStatus(TripStatus status) { 51 | this.status = status; 52 | } 53 | 54 | @Override 55 | public String toString() { 56 | return "Trip{" + "id=" + id + ", status=" + status + ", driverId=" + driverId + ", passengerId=" + passengerId + "}"; 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /passenger-management/src/main/java/pl/piomin/services/passenger/model/Trip.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.services.passenger.model; 2 | 3 | import java.io.Serializable; 4 | import java.util.Date; 5 | 6 | public class Trip implements Serializable { 7 | 8 | private Long id; 9 | private Date startDate; 10 | private Long driverId; 11 | private Long passengerId; 12 | private TripStatus status; 13 | 14 | public Long getId() { 15 | return id; 16 | } 17 | 18 | public void setId(Long id) { 19 | this.id = id; 20 | } 21 | 22 | public Date getStartDate() { 23 | return startDate; 24 | } 25 | 26 | public void setStartDate(Date startDate) { 27 | this.startDate = startDate; 28 | } 29 | 30 | public Long getDriverId() { 31 | return driverId; 32 | } 33 | 34 | public void setDriverId(Long driverId) { 35 | this.driverId = driverId; 36 | } 37 | 38 | public Long getPassengerId() { 39 | return passengerId; 40 | } 41 | 42 | public void setPassengerId(Long passengerId) { 43 | this.passengerId = passengerId; 44 | } 45 | 46 | public TripStatus getStatus() { 47 | return status; 48 | } 49 | 50 | public void setStatus(TripStatus status) { 51 | this.status = status; 52 | } 53 | 54 | @Override 55 | public String toString() { 56 | return "Trip{" + "id=" + id + ", status=" + status + ", driverId=" + driverId + ", passengerId=" + passengerId + "}"; 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /passenger-management/src/main/java/pl/piomin/services/passenger/PassengerConfiguration.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.services.passenger; 2 | 3 | import pl.piomin.services.passenger.subscribe.PassengerSubscriber; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.data.redis.connection.RedisConnectionFactory; 9 | import org.springframework.data.redis.listener.ChannelTopic; 10 | import org.springframework.data.redis.listener.RedisMessageListenerContainer; 11 | import org.springframework.data.redis.listener.adapter.MessageListenerAdapter; 12 | import org.springframework.data.redis.repository.configuration.EnableRedisRepositories; 13 | 14 | @Configuration 15 | @EnableRedisRepositories 16 | public class PassengerConfiguration { 17 | 18 | @Autowired 19 | RedisConnectionFactory redisConnectionFactory; 20 | 21 | @Bean 22 | RedisMessageListenerContainer container() { 23 | RedisMessageListenerContainer container = new RedisMessageListenerContainer(); 24 | container.addMessageListener(messageListener(), topic()); 25 | container.setConnectionFactory(redisConnectionFactory); 26 | return container; 27 | } 28 | 29 | @Bean 30 | MessageListenerAdapter messageListener() { 31 | return new MessageListenerAdapter(new PassengerSubscriber()); 32 | } 33 | 34 | @Bean 35 | ChannelTopic topic() { 36 | return new ChannelTopic("trips"); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /driver-management/src/test/java/pl/piomin/services/driver/DriverRepositoryIntegrationTests.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.services.driver; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.boot.test.autoconfigure.data.redis.DataRedisTest; 6 | import org.springframework.data.geo.Point; 7 | import org.springframework.test.context.DynamicPropertyRegistry; 8 | import org.springframework.test.context.DynamicPropertySource; 9 | import org.testcontainers.containers.GenericContainer; 10 | import org.testcontainers.junit.jupiter.Container; 11 | import org.testcontainers.junit.jupiter.Testcontainers; 12 | import pl.piomin.services.driver.model.Driver; 13 | import pl.piomin.services.driver.model.DriverStatus; 14 | import pl.piomin.services.driver.repository.DriverRepository; 15 | 16 | @DataRedisTest 17 | @Testcontainers 18 | public class DriverRepositoryIntegrationTests { 19 | 20 | @Container 21 | static final GenericContainer redis = new GenericContainer("redis:latest") 22 | .withExposedPorts(6379); 23 | 24 | @DynamicPropertySource 25 | static void redisProperties(DynamicPropertyRegistry registry) { 26 | registry.add("spring.data.redis.port", redis::getFirstMappedPort); 27 | } 28 | 29 | @Autowired 30 | DriverRepository repository; 31 | 32 | @Test 33 | public void testAdd() { 34 | Driver driver = new Driver(); 35 | driver.setName("John Smith"); 36 | driver.setStatus(DriverStatus.WAITING); 37 | driver.setLocation(new Point(10, 20)); 38 | repository.save(driver); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /passenger-management/src/main/java/pl/piomin/services/passenger/subscribe/PassengerSubscriber.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.services.passenger.subscribe; 2 | 3 | import java.io.IOException; 4 | import java.util.Optional; 5 | 6 | import com.fasterxml.jackson.databind.ObjectMapper; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import pl.piomin.services.passenger.model.Passenger; 10 | import pl.piomin.services.passenger.model.Trip; 11 | import pl.piomin.services.passenger.repository.PassengerRepository; 12 | 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.data.redis.connection.Message; 15 | import org.springframework.data.redis.connection.MessageListener; 16 | import org.springframework.stereotype.Service; 17 | 18 | @Service 19 | public class PassengerSubscriber implements MessageListener { 20 | 21 | private final Logger LOGGER = LoggerFactory.getLogger(PassengerSubscriber.class); 22 | 23 | @Autowired 24 | PassengerRepository repository; 25 | ObjectMapper mapper = new ObjectMapper(); 26 | 27 | @Override 28 | public void onMessage(Message message, byte[] bytes) { 29 | try { 30 | Trip trip = mapper.readValue(message.getBody(), Trip.class); 31 | LOGGER.info("Message received: {}", trip.toString()); 32 | Optional optPassenger = repository.findById(trip.getDriverId()); 33 | if (optPassenger.isPresent()) { 34 | repository.save(optPassenger.get()); 35 | } 36 | } catch (IOException e) { 37 | LOGGER.error("Error reading message", e); 38 | } 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /driver-management/src/main/java/pl/piomin/services/driver/DriverConfiguration.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.services.driver; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import pl.piomin.services.driver.subscribe.DriverSubscriber; 5 | 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | import org.springframework.data.redis.connection.RedisConnectionFactory; 10 | import org.springframework.data.redis.listener.ChannelTopic; 11 | import org.springframework.data.redis.listener.RedisMessageListenerContainer; 12 | import org.springframework.data.redis.listener.adapter.MessageListenerAdapter; 13 | import org.springframework.data.redis.repository.configuration.EnableRedisRepositories; 14 | 15 | @Configuration 16 | @EnableRedisRepositories 17 | public class DriverConfiguration { 18 | 19 | @Value("${sample.topic.name}") 20 | String topicName; 21 | 22 | @Autowired 23 | RedisConnectionFactory redisConnectionFactory; 24 | 25 | @Bean 26 | RedisMessageListenerContainer container() { 27 | RedisMessageListenerContainer container = new RedisMessageListenerContainer(); 28 | container.addMessageListener(messageListener(), topic()); 29 | container.setConnectionFactory(redisConnectionFactory); 30 | return container; 31 | } 32 | 33 | @Bean 34 | MessageListenerAdapter messageListener() { 35 | return new MessageListenerAdapter(new DriverSubscriber()); 36 | } 37 | 38 | @Bean 39 | ChannelTopic topic() { 40 | return new ChannelTopic(topicName); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /trip-management/src/main/java/pl/piomin/services/trip/web/TripController.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.services.trip.web; 2 | 3 | import java.util.List; 4 | import java.util.Optional; 5 | 6 | import com.fasterxml.jackson.core.JsonProcessingException; 7 | import pl.piomin.services.trip.model.Trip; 8 | import pl.piomin.services.trip.publish.TripPublisher; 9 | import pl.piomin.services.trip.repository.TripRepository; 10 | 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.web.bind.annotation.GetMapping; 13 | import org.springframework.web.bind.annotation.PathVariable; 14 | import org.springframework.web.bind.annotation.PostMapping; 15 | import org.springframework.web.bind.annotation.RequestBody; 16 | import org.springframework.web.bind.annotation.RequestMapping; 17 | import org.springframework.web.bind.annotation.RestController; 18 | 19 | @RestController 20 | @RequestMapping("/trips") 21 | public class TripController { 22 | 23 | @Autowired 24 | TripPublisher publisher; 25 | @Autowired 26 | TripRepository repository; 27 | 28 | @PostMapping 29 | public Trip create(@RequestBody Trip trip) { 30 | trip = repository.save(trip); 31 | try { 32 | publisher.publish(trip); 33 | } catch (JsonProcessingException e) { 34 | e.printStackTrace(); 35 | } 36 | return trip; 37 | } 38 | 39 | 40 | @GetMapping("/{id}") 41 | public Trip findById(@PathVariable("id") Long id) { 42 | Optional optTrip = repository.findById(id); 43 | if (optTrip.isPresent()) { 44 | return optTrip.get(); 45 | } else { 46 | return null; 47 | } 48 | } 49 | 50 | @GetMapping 51 | public List findAll() { 52 | return (List) repository.findAll(); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /trip-management/src/main/java/pl/piomin/services/trip/model/Trip.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.services.trip.model; 2 | 3 | import java.io.Serializable; 4 | import java.util.Date; 5 | 6 | import org.springframework.data.annotation.Id; 7 | import org.springframework.data.redis.core.RedisHash; 8 | import org.springframework.data.redis.core.index.Indexed; 9 | 10 | @RedisHash("trip") 11 | public class Trip implements Serializable { 12 | 13 | @Id 14 | private Long id; 15 | private Date startDate; 16 | @Indexed 17 | private Long driverId; 18 | @Indexed 19 | private Long passengerId; 20 | private TripStatus status; 21 | 22 | public Long getId() { 23 | return id; 24 | } 25 | 26 | public void setId(Long id) { 27 | this.id = id; 28 | } 29 | 30 | public Date getStartDate() { 31 | return startDate; 32 | } 33 | 34 | public void setStartDate(Date startDate) { 35 | this.startDate = startDate; 36 | } 37 | 38 | public Long getDriverId() { 39 | return driverId; 40 | } 41 | 42 | public void setDriverId(Long driverId) { 43 | this.driverId = driverId; 44 | } 45 | 46 | public Long getPassengerId() { 47 | return passengerId; 48 | } 49 | 50 | public void setPassengerId(Long passengerId) { 51 | this.passengerId = passengerId; 52 | } 53 | 54 | public TripStatus getStatus() { 55 | return status; 56 | } 57 | 58 | public void setStatus(TripStatus status) { 59 | this.status = status; 60 | } 61 | 62 | @Override 63 | public String toString() { 64 | return "Trip{" + 65 | "id=" + id + 66 | ", startDate=" + startDate + 67 | ", driverId=" + driverId + 68 | ", passengerId=" + passengerId + 69 | ", status=" + status + 70 | '}'; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /driver-management/src/main/java/pl/piomin/services/driver/subscribe/DriverSubscriber.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.services.driver.subscribe; 2 | 3 | import java.io.IOException; 4 | import java.util.Optional; 5 | 6 | import com.fasterxml.jackson.databind.ObjectMapper; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import pl.piomin.services.driver.model.Driver; 10 | import pl.piomin.services.driver.model.DriverStatus; 11 | import pl.piomin.services.driver.model.Trip; 12 | import pl.piomin.services.driver.model.TripStatus; 13 | import pl.piomin.services.driver.repository.DriverRepository; 14 | 15 | import org.springframework.beans.factory.annotation.Autowired; 16 | import org.springframework.data.redis.connection.Message; 17 | import org.springframework.data.redis.connection.MessageListener; 18 | import org.springframework.stereotype.Service; 19 | 20 | @Service 21 | public class DriverSubscriber implements MessageListener { 22 | 23 | private final Logger LOGGER = LoggerFactory.getLogger(DriverSubscriber.class); 24 | 25 | @Autowired 26 | DriverRepository repository; 27 | ObjectMapper mapper = new ObjectMapper(); 28 | 29 | @Override 30 | public void onMessage(Message message, byte[] bytes) { 31 | try { 32 | Trip trip = mapper.readValue(message.getBody(), Trip.class); 33 | LOGGER.info("Message received: {}", trip.toString()); 34 | Optional optDriver = repository.findById(trip.getDriverId()); 35 | if (optDriver.isPresent()) { 36 | Driver driver = optDriver.get(); 37 | if (trip.getStatus() == TripStatus.DONE) 38 | driver.setStatus(DriverStatus.WAITING); 39 | else 40 | driver.setStatus(DriverStatus.BUSY); 41 | repository.save(driver); 42 | } 43 | } catch (IOException e) { 44 | LOGGER.error("Error reading message", e); 45 | } 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /driver-management/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | pl.piomin.services 7 | sample-redis-microservices 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | driver-management 13 | 14 | 15 | ${project.artifactId} 16 | 17 | 18 | 19 | 20 | org.springframework.boot 21 | spring-boot-starter-web 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-data-redis 26 | 27 | 28 | org.springframework.cloud 29 | spring-cloud-starter-config 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-test 34 | test 35 | 36 | 37 | org.testcontainers 38 | testcontainers 39 | 1.21.4 40 | test 41 | 42 | 43 | org.testcontainers 44 | junit-jupiter 45 | 1.21.4 46 | test 47 | 48 | 49 | -------------------------------------------------------------------------------- /trip-management/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | pl.piomin.services 7 | sample-redis-microservices 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | trip-management 13 | 14 | 15 | ${project.artifactId} 16 | 17 | 18 | 19 | 20 | org.springframework.boot 21 | spring-boot-starter-web 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-data-redis 26 | 27 | 28 | org.springframework.cloud 29 | spring-cloud-starter-config 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-test 34 | test 35 | 36 | 37 | org.testcontainers 38 | testcontainers 39 | 1.21.4 40 | test 41 | 42 | 43 | org.testcontainers 44 | junit-jupiter 45 | 1.21.4 46 | test 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /passenger-management/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | pl.piomin.services 7 | sample-redis-microservices 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | passenger-management 13 | 14 | 15 | ${project.artifactId} 16 | 17 | 18 | 19 | 20 | org.springframework.boot 21 | spring-boot-starter-web 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-data-redis 26 | 27 | 28 | org.springframework.cloud 29 | spring-cloud-starter-config 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-test 34 | test 35 | 36 | 37 | org.testcontainers 38 | testcontainers 39 | 1.21.4 40 | test 41 | 42 | 43 | org.testcontainers 44 | junit-jupiter 45 | 1.21.4 46 | test 47 | 48 | 49 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | org.springframework.boot 9 | spring-boot-starter-parent 10 | 3.5.9 11 | 12 | 13 | 14 | pl.piomin.services 15 | sample-redis-microservices 16 | 1.0-SNAPSHOT 17 | 18 | 19 | piomin_sample-redis-microservices 20 | piomin 21 | https://sonarcloud.io 22 | 21 23 | 24 | 25 | 26 | driver-management 27 | trip-management 28 | passenger-management 29 | config-server 30 | 31 | pom 32 | 33 | 34 | 35 | 36 | org.springframework.boot 37 | spring-boot-maven-plugin 38 | 39 | 40 | org.jacoco 41 | jacoco-maven-plugin 42 | 0.8.14 43 | 44 | 45 | 46 | prepare-agent 47 | 48 | 49 | 50 | report 51 | test 52 | 53 | report 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | org.springframework.cloud 65 | spring-cloud-dependencies 66 | 2025.0.0 67 | pom 68 | import 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /trip-management/src/test/java/pl/piomin/services/trip/TripControllerIntegrationTests.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.services.trip; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.boot.test.context.TestConfiguration; 7 | import org.springframework.boot.test.web.client.TestRestTemplate; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.data.redis.connection.RedisConnectionFactory; 10 | import org.springframework.data.redis.listener.ChannelTopic; 11 | import org.springframework.data.redis.listener.RedisMessageListenerContainer; 12 | import org.springframework.data.redis.listener.adapter.MessageListenerAdapter; 13 | import org.springframework.test.context.DynamicPropertyRegistry; 14 | import org.springframework.test.context.DynamicPropertySource; 15 | import org.testcontainers.containers.GenericContainer; 16 | import org.testcontainers.junit.jupiter.Container; 17 | import org.testcontainers.junit.jupiter.Testcontainers; 18 | import pl.piomin.services.trip.model.Trip; 19 | 20 | import java.util.Date; 21 | import java.util.concurrent.BlockingQueue; 22 | import java.util.concurrent.LinkedBlockingQueue; 23 | 24 | import static org.junit.jupiter.api.Assertions.assertEquals; 25 | import static org.junit.jupiter.api.Assertions.assertNotNull; 26 | 27 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 28 | @Testcontainers 29 | public class TripControllerIntegrationTests { 30 | 31 | static BlockingQueue queue = new LinkedBlockingQueue<>(); 32 | 33 | @TestConfiguration 34 | static class TripTestConfiguration { 35 | @Autowired 36 | RedisConnectionFactory redisConnectionFactory; 37 | @Autowired 38 | ChannelTopic topic; 39 | 40 | @Bean 41 | RedisMessageListenerContainer container() { 42 | RedisMessageListenerContainer container = new RedisMessageListenerContainer(); 43 | container.addMessageListener(messageListener(), topic); 44 | container.setConnectionFactory(redisConnectionFactory); 45 | return container; 46 | } 47 | 48 | @Bean 49 | MessageListenerAdapter messageListener() { 50 | return new MessageListenerAdapter(new TripTestListener(queue)); 51 | } 52 | } 53 | 54 | @Container 55 | static final GenericContainer redis = new GenericContainer("redis:latest") 56 | .withExposedPorts(6379); 57 | 58 | @DynamicPropertySource 59 | static void redisProperties(DynamicPropertyRegistry registry) { 60 | registry.add("spring.data.redis.port", redis::getFirstMappedPort); 61 | } 62 | 63 | @Autowired 64 | TestRestTemplate template; 65 | 66 | @Test 67 | public void testCreate() throws InterruptedException { 68 | Trip trip = new Trip(); 69 | trip.setStartDate(new Date()); 70 | trip.setDriverId(1L); 71 | trip.setPassengerId(1L); 72 | trip = template.postForObject("/trips", trip, Trip.class); 73 | assertNotNull(trip, "Trip null!"); 74 | assertNotNull(trip.getId(), "Trip id null!"); 75 | 76 | Trip t = queue.take(); 77 | assertNotNull(t); 78 | assertEquals(t.getId(), trip.getId()); 79 | } 80 | 81 | } 82 | --------------------------------------------------------------------------------