Skip to content
This repository has been archived by the owner on Jun 3, 2022. It is now read-only.

Developer's Guide

Nordine Bittich edited this page Mar 22, 2020 · 8 revisions

Before running anything

sh install-local.sh

Setup your module

Notes

  • a new microservice should be added on the folder microservices
  • if it is a rest service, you must put it in the web module. if it is a kafka service, you must put it in the kafka module
  • difference between a rest and and kafka module is that in case of kafka, the services will communicate with kafka & sometimes feign (rest services) through the rest gateway (e.g upload-rest), while the rest services are "discoverable" through zookeeper (see Service discovery) and can communicate in that way (also with Feign). The rest services also expose rest endpoints.
  • This setup is common for each kind of services

Steps

  • In module directory, add a DockerFile:
FROM amazoncorretto:11
VOLUME /usr/app
ARG JAR_FILE
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar", "app.jar","-server"]
  • Simple pom.xml file example
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>atriangle-kafka</artifactId> <!-- change in case of web -->
        <groupId>tech.artcoded</groupId>
        <version>0.1.5-SNAPSHOT</version> <!-- make sure to update with the latest the version -->
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <name>A Triangle - MyService-KAFA</name>

    <artifactId>atriangle-mymicroservice</artifactId>
    <properties>
        <docker.image.name>atriangle/mymicroservice</docker.image.name> <!-- docker image name -->
    </properties>

    <dependencies>
        <dependency>
            <groupId>tech.artcoded</groupId>
            <artifactId>atriangle-core-kafka</artifactId> <!-- common to every project -->
        </dependency>
        <dependency>
            <groupId>tech.artcoded</groupId>
            <artifactId>atriangle-shared-config</artifactId> <!-- shared config -->
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>
    <profiles>
        <profile>
            <id>docker</id>
            <activation>
                <property>
                    <name>docker</name>
                </property>
            </activation>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.codehaus.mojo</groupId>  <!-- docker image -->
                        <artifactId>exec-maven-plugin</artifactId>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>
    <build>
        <finalName>atriangle-mymicroservice</finalName> 
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
  • in src/main/resources, create an application.yml file and add the following:
application:
  basePath: ${PROJECT_BASE_PATH:/${user.home}/mysercice}
server:
  port: 0
spring:
  application:
    name: MyService
  profiles:
    include: kafka
  • create file src/main/java/tech/artcoded/atriangle/myservice/MyServiceApplicaton.java
  • import kafka config to your application:
@SpringBootApplication
@Import({KafkaConfig.class})
public class MyServiceApplicaton {
  public static void main(String[] args) {
    SpringApplication.run(MyServiceApplicaton.class, args);
  }
}

Logger Action

In order to log an action to elasticsearch, follow these steps:

  • run the tech.artcoded.atriangle.logsink.LogSinkApplication (or run the docker image)

  • run the tech.artcoded.atriangle.rest.RestProxyGatewayApplication (or run the docker image)

  • Inject & Usage of LoggerAction

@Service
public class MyService {
  private final LoggerAction loggerAction;

  @Inject
  public MyService(LoggerAction loggerAction) {
    this.loggerAction = loggerAction;
  }
  
  public void doStuff(){
    // the first argument is the correlation id supplier, 
    // it is mainly used when you want to correlate logs
    // the following arguments are the same as if you were
    // using String.format("do stuff %s", "one thing");
    loggerAction.info(IdGenerators::get,"do stuff %s", "one thing");
  }
}

Create a "kafka" microservice

Notes

  • By adding atriangle-kafka-core and KafkaConfig, you are already able to communicate with kafka
  • To keep a certain logic, you must create you own event and let the event dispatcher dispatches it

Steps

  • add the following to your application.yml file:
out:
  topic: my-event-out # topic to produce

spring:
  kafka:
    template:
      default-topic: my-event # topic to consume
  • Add the new topics to event-dispatcher:
    • in microservices/kafka/event-dispatcher/src/main/resources/application.yml:
event:
  dispatcher:
    # .. other
    my-event-topic: my-event
    my-event-topic-out: my-event-out
  • Add new enums to EventType:
public enum EventType {
 // other enums...
  MY_EVENT,
  MY_EVENT_OUT,
}
  • Add routing to microservices/kafka/event-dispatcher/src/main/java/tech/artcoded/atriangle/eventdispatcher/EventDispatcherSink.java:
  // ... others
  @Value("${event.dispatcher.my-event-topic}")
  private String myEventTopic;
  @Value("${event.dispatcher.my-event-topic-out}")
  private String myEventTopicOut;

 // ...
 optionalKafkaEvent.ifPresent(kafkaEvent -> {
      switch (kafkaEvent.getEventType()) {
        case MY_EVENT:
          log.info("result of send event: {}", sendEvent.apply(myEventTopic));
          break;
      }
    });
  • Create a simple Consumer / Producer:
@Component
@Slf4j
public class MyConsumer implements ATriangleConsumer<String, String> {

  private final ObjectMapperWrapper mapperWrapper;

  @Value("${out.topic}")
  @Getter
  private String outTopic;

  @Inject
  public MyConsumer(ObjectMapperWrapper mapperWrapper) {
    this.mapperWrapper = mapperWrapper;
  }


  @Override
  public Map<String, String> consume(ConsumerRecord<String, String> record) throws Exception {
    String kafkaEventJson = record.value();

    // parse the event
    Optional<KafkaEvent> optionalKafkaEvent = mapperWrapper.deserialize(kafkaEventJson, KafkaEvent.class);
    KafkaEvent kafkaEvent = optionalKafkaEvent.orElseThrow(() -> new RuntimeException("event could not be parsed"));
    Optional<MyEvent> optionalMyEvent = mapperWrapper.deserialize(kafkaEvent.getEvent(), MyEvent.class);
    MyEvent event = optionalMyEvent.orElseThrow(() -> new RuntimeException("event could not be parsed"));

    // do something useful with MyEvent
    log.info("receive{} ", event.getMessage());
    MyEventOut eventOut = MyEventOut.builder().message(event.getMessage()).build();

    // response out
    String eventOutId = IdGenerators.get();
    KafkaEvent kafkaEventOut = kafkaEvent.toBuilder()
                                                 .id(eventOutId)
                                                 .eventType(EventType.MY_EVENT_OUT)
                                                 .event(mapperWrapper.serialize(eventOut))
                                                 .build();

    return Map.of(eventOutId, mapperWrapper.serialize(kafkaEventOut)); // message will be send to the out topic
  }


}

Create a "web" microservice

  • Add the following dependency:
 <dependency>
            <groupId>tech.artcoded</groupId>
            <artifactId>atriangle-core-rest</artifactId>
 </dependency>
  • Include the following profile:
spring:
  application:
    name: MyService # important for zuul
  profiles:
    include: kafka, zookeeper, rest
  • On the main app, add the SwaggerConfig and enable discovery:
@SpringBootApplication
@Import({KafkaConfig.class, SwaggerConfig.class})
@EnableDiscoveryClient
public class MyServiceApplicaton {
  public static void main(String[] args) {
    SpringApplication.run(MyServiceApplicaton.class, args);
  }
}
  • Create a controller:
@CrossOriginRestController
@ApiOperation("Hello Rest")
@Slf4j
public class MyController implements PingControllerTrait {

  @GetMapping(path = "/hello")
  public ResponseEntity<String> hello() {
    return ResponseEntity.ok("hello");
  }
}
  • add the zuul config to common/shared-config/src/main/resources/application-zuul.yml:
 hello:
      path: /api/hello/**
      serviceId: MyService # spring.application.name

Release

sh release.sh 0.1.5 0.1.6