{"id":829,"date":"2020-03-30T15:00:00","date_gmt":"2020-03-30T15:00:00","guid":{"rendered":"http:\/\/bullyrooks.com\/index.php\/2020\/04\/10\/simple-spring-boot-service-to-kubernetes-application-step-15-34e1bba8351b\/"},"modified":"2021-02-04T02:05:47","modified_gmt":"2021-02-04T02:05:47","slug":"simple-spring-boot-service-to-kubernetes-application-step-15-34e1bba8351b","status":"publish","type":"post","link":"https:\/\/bullyrooks.com\/index.php\/2020\/03\/30\/simple-spring-boot-service-to-kubernetes-application-step-15-34e1bba8351b\/","title":{"rendered":"Messaging and Event Driven Design"},"content":{"rendered":"\n<p class=\"graf graf--p graf-after--h3 graf--trailing\" id=\"2f92\">In order publish messages, we need a message broker and add some logic to use the message broker. We\u2019re going to use a cloud based SaaS service as a message broker and use spring cloud stream to interact with it.<\/p>\n\n\n\n<h3 class=\"graf graf--h3 graf--leading wp-block-heading\" id=\"2bfb\">Setup the Message&nbsp;Broker<\/h3>\n\n\n\n<p class=\"graf graf--p graf-after--h3\" id=\"69b7\">We\u2019ll need a message broker in order to publish and we can stand up a free one at <a class=\"markup--anchor markup--p-anchor\" href=\"https:\/\/www.cloudamqp.com\/\" target=\"_blank\" rel=\"noopener\" data-href=\"https:\/\/www.cloudamqp.com\/\">cloudamqp<\/a>. Go ahead and register an account. Once that is done, create a new instance. We\u2019re going to create a free instance called <code class=\"markup--code markup--p-code\">medium<\/code> in whatever region you want. When that is done, click on the instance to get the details. We\u2019re going to need the host, user and password from here.<\/p>\n\n\n\n<h3 class=\"graf graf--h3 graf-after--p wp-block-heading\" id=\"3ae1\">Write the Publisher Logic<\/h3>\n\n\n\n<p class=\"graf graf--p graf-after--h3\" id=\"a504\">Create a new package called <code class=\"markup--code markup--p-code\">com.brianrook.medium.customer.messaging<\/code> and in that package create 2 more sub packages for <code class=\"markup--code markup--p-code\">mapper <\/code>and <code class=\"markup--code markup--p-code\">message<\/code>. First create the message payload in <code class=\"markup--code markup--p-code\">message <\/code>using a class called <code class=\"markup--code markup--p-code\">CustomerCreatedMessage<\/code>:<\/p>\n\n\n\n<pre id=\"82de\" class=\"wp-block-code graf graf--pre graf-after--p\"><code>package com.brianrook.medium.customer.messaging.message;\n\nimport lombok.Data;\n\n@Data\npublic class CustomerCreatedMessage {\n    private Long customerId;\n    private String firstName;\n    private String lastName;\n    private String phoneNumber;\n    private String email;\n}<\/code><\/pre>\n\n\n\n<p class=\"graf graf--p graf-after--pre\" id=\"c094\">Create a mapper interface under <code class=\"markup--code markup--p-code\">mapper<\/code> called <code class=\"markup--code markup--p-code\">CustomerMessageMapper <\/code>with this content:<\/p>\n\n\n\n<pre id=\"1eda\" class=\"wp-block-code graf graf--pre graf-after--p\"><code>package com.brianrook.medium.customer.messaging.mapper;\n\nimport com.brianrook.medium.customer.messaging.message.CustomerCreatedMessage;\nimport com.brianrook.medium.customer.service.model.Customer;\nimport org.mapstruct.Mapper;\nimport org.mapstruct.factory.Mappers;\n\n@Mapper\npublic interface CustomerMessageMapper {\n    CustomerMessageMapper <em class=\"markup--em markup--pre-em\">INSTANCE <\/em>= Mappers.<em class=\"markup--em markup--pre-em\">getMapper<\/em>(CustomerMessageMapper.class);\n\n    CustomerCreatedMessage customerToCustomerCreatedMessage(Customer customer);\n}<\/code><\/pre>\n\n\n\n<p class=\"graf graf--p graf-after--pre\" id=\"ec74\">in <code class=\"markup--code markup--p-code\">com.brianrook.medium.customer.config<\/code> create<code class=\"markup--code markup--p-code\">CustomerCreateBinding<\/code>:<\/p>\n\n\n\n<pre id=\"4332\" class=\"wp-block-code graf graf--pre graf-after--p\"><code>package com.brianrook.medium.customer.messaging;\n\nimport org.springframework.cloud.stream.annotation.Output;\nimport org.springframework.messaging.MessageChannel;\n\npublic interface CustomerCreateBinding {\n\n    @Output(\"customerCreateChannel\")\n    MessageChannel customerCreate();\n}<\/code><\/pre>\n\n\n\n<p class=\"graf graf--p graf-after--pre\" id=\"3634\">and in <code class=\"markup--code markup--p-code\">com.brianrook.medium.customer.messaging <\/code>create <code class=\"markup--code markup--p-code\">CustomerCreatePublisher<\/code><\/p>\n\n\n\n<pre id=\"a24d\" class=\"wp-block-code graf graf--pre graf-after--p\"><code>package com.brianrook.medium.customer.messaging;\n\nimport com.brianrook.medium.customer.messaging.mapper.CustomerMessageMapper;\nimport com.brianrook.medium.customer.messaging.message.CustomerCreatedMessage;\nimport com.brianrook.medium.customer.service.model.Customer;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.cloud.stream.annotation.EnableBinding;\nimport org.springframework.messaging.Message;\nimport org.springframework.messaging.support.MessageBuilder;\nimport org.springframework.stereotype.Component;\n\n@Component\n@EnableBinding(CustomerCreateBinding.class)\npublic class CustomerCreatePublisher {\n\n    @Autowired\n    CustomerCreateBinding customerCreateBinding;\n\n    public void publishCustomerCreate(Customer customer) {\n        CustomerCreatedMessage customerMessage = CustomerMessageMapper.<em class=\"markup--em markup--pre-em\">INSTANCE<\/em>.customerToCustomerCreatedMessage(customer);\n        Message&lt;CustomerCreatedMessage&gt; msg = MessageBuilder.<em class=\"markup--em markup--pre-em\">withPayload<\/em>(customerMessage).build();\n\n        customerCreateBinding.customerCreate().send(msg);\n    }\n}<\/code><\/pre>\n\n\n\n<p class=\"graf graf--p graf-after--pre\" id=\"6aa3\">and hook it into our service CustomerService:<\/p>\n\n\n\n<pre id=\"3592\" class=\"wp-block-preformatted graf graf--pre graf-after--p\">...<\/pre>\n\n\n\n<pre id=\"5486\" class=\"wp-block-code graf graf--pre graf-after--pre\"><code>@Autowired\nCustomerCreatePublisher customerCreatePublisher;<\/code><\/pre>\n\n\n\n<pre id=\"12ef\" class=\"wp-block-code graf graf--pre graf-after--pre\"><code>...<\/code><\/pre>\n\n\n\n<pre id=\"e053\" class=\"wp-block-code graf graf--pre graf-after--pre\"><code>public Customer saveCustomer(Customer customer) {\n    if (customerExists(customer))\n    {\n        throw new CreateCustomerException(String.<em class=\"markup--em markup--pre-em\">format<\/em>(\"customer with email: %s already exists\", customer.getEmail()));\n    }\n    Customer savedCustomer = persistCustomer(customer);\n    customerCreatePublisher.publishCustomerCreate(savedCustomer);\n\n    return savedCustomer;\n}<\/code><\/pre>\n\n\n\n<p class=\"graf graf--p graf-after--pre\" id=\"4c1f\">And finally we\u2019ll need to configure our application, add this configuration to <code class=\"markup--code markup--p-code\">application.yaml<\/code>:<\/p>\n\n\n\n<pre id=\"ac94\" class=\"wp-block-code graf graf--pre graf-after--p\"><code>spring:<\/code><\/pre>\n\n\n\n<pre id=\"d574\" class=\"wp-block-code graf graf--pre graf-after--pre\"><code>...<\/code><\/pre>\n\n\n\n<pre id=\"6682\" class=\"wp-block-code graf graf--pre graf-after--pre\"><code>  cloud:\n    stream:\n      bindings:\n        output:\n          destination: queue.customer.create\n          content-type: application\/json\n  rabbitmq:\n    addresses: amqp:\/\/shrimp.rmq.cloudamqp.com\/c***j<\/code><\/pre>\n\n\n\n<blockquote class=\"wp-block-quote graf graf--blockquote graf-after--pre is-layout-flow wp-block-quote-is-layout-flow\" id=\"8678\"><p>Here we\u2019re telling spring boot to create a rabbit destination on the instance and where to connect to. Make sure to strip out the username and password from the url and replace with your own instance name.<\/p><\/blockquote>\n\n\n\n<p class=\"graf graf--p graf-after--blockquote\" id=\"997b\">We also need to add the rabbit binder libraries to the <code class=\"markup--code markup--p-code\">pom.xml<\/code><\/p>\n\n\n\n<pre id=\"18e0\" class=\"wp-block-code graf graf--pre graf-after--p\"><code>&lt;dependency&gt;\n   &lt;groupId&gt;org.springframework.cloud&lt;\/groupId&gt;\n   &lt;artifactId&gt;spring-cloud-starter-stream-rabbit&lt;\/artifactId&gt;\n&lt;\/dependency&gt;\n&lt;dependency&gt;\n   &lt;groupId&gt;org.springframework.cloud&lt;\/groupId&gt;\n   &lt;artifactId&gt;spring-cloud-stream-binder-rabbit&lt;\/artifactId&gt;\n&lt;\/dependency&gt;<\/code><\/pre>\n\n\n\n<h3 class=\"graf graf--h3 graf-after--pre wp-block-heading\" id=\"b419\">Testing<\/h3>\n\n\n\n<p class=\"graf graf--p graf-after--h3\" id=\"7a64\">Update <code class=\"markup--code markup--p-code\">CustomerControllerTest<\/code> to test that we can publish this message.<\/p>\n\n\n\n<pre id=\"411f\" class=\"wp-block-code graf graf--pre graf-after--p\"><code>...<\/code><\/pre>\n\n\n\n<pre id=\"4b97\" class=\"wp-block-code graf graf--pre graf-after--pre\"><code>@Autowired\nMessageCollector messageCollector;\n@Autowired\nAppointmentCreateBinding appointmentCreateBinding;<\/code><\/pre>\n\n\n\n<pre id=\"5501\" class=\"wp-block-code graf graf--pre graf-after--pre\"><code>...<\/code><\/pre>\n\n\n\n<pre id=\"3c60\" class=\"wp-block-code graf graf--pre graf-after--pre\"><code>@Test\npublic void testAddCustomerSuccess() throws URISyntaxException, JsonProcessingException {<\/code><\/pre>\n\n\n\n<pre id=\"986c\" class=\"wp-block-code graf graf--pre graf-after--pre\"><code>...<\/code><\/pre>\n\n\n\n<pre id=\"a902\" class=\"wp-block-code graf graf--pre graf-after--pre\"><code>    \/\/validate AMQP\n    Message&lt;String&gt; publishedMessage = (Message&lt;String&gt;)messageCollector\n            .forChannel(customerCreateBinding.customerCreate())\n            .poll();\n<em class=\"markup--em markup--pre-em\">assertThat<\/em>(publishedMessage).isNotNull();\n    ObjectMapper om = new ObjectMapper().registerModule(new JavaTimeModule());\n\n    CustomerCreatedMessage appointmentMessage = om.readValue(\n            publishedMessage.getPayload(),\n            CustomerCreatedMessage.class);\n<em class=\"markup--em markup--pre-em\">assertThat<\/em>(appointmentMessage.getCustomerId()).isGreaterThan(0l);\n}<\/code><\/pre>\n\n\n\n<pre id=\"9229\" class=\"wp-block-preformatted graf graf--pre graf-after--pre\">...<\/pre>\n\n\n\n<pre id=\"26c9\" class=\"wp-block-code graf graf--pre graf-after--pre\"><code>@Test\npublic void testAddCustomerConflict() throws URISyntaxException {<\/code><\/pre>\n\n\n\n<pre id=\"cbc1\" class=\"wp-block-code graf graf--pre graf-after--pre\"><code>...\n\n    \/\/validate AMQP\n<em class=\"markup--em markup--pre-em\">assertThat<\/em>(messageCollector\n            .forChannel(customerCreateBinding.customerCreate())\n            .isEmpty()).isTrue();\n}<\/code><\/pre>\n\n\n\n<blockquote class=\"wp-block-quote graf graf--blockquote graf-after--pre is-layout-flow wp-block-quote-is-layout-flow\" id=\"31b9\"><p>Here we\u2019re using the spring application context to hook into the spring bindings used to talk to our AMQP broker. We\u2019re essentially wiring in before the logic to publish a message is executed and pulling the messages out of the pipeline before they get sent. We can also confirm that messages are not sent in the case of errors.<\/p><\/blockquote>\n\n\n\n<p class=\"graf graf--p graf-after--blockquote\" id=\"f9d0\">We\u2019ve also added significant functionality so lets update our application version using semantic versioning. Update the <code class=\"markup--code markup--p-code\">pom.xml<\/code>:<\/p>\n\n\n\n<pre id=\"5484\" class=\"wp-block-code graf graf--pre graf-after--p\"><code>&lt;groupId&gt;com.brianrook.medium&lt;\/groupId&gt;\n&lt;artifactId&gt;medium-customer&lt;\/artifactId&gt;\n&lt;version&gt;0.1.0-SNAPSHOT&lt;\/version&gt;\n&lt;name&gt;medium-customer&lt;\/name&gt;<\/code><\/pre>\n\n\n\n<p class=\"graf graf--p graf-after--pre\" id=\"a183\">I was also having trouble with the <code class=\"markup--code markup--p-code\">LoggingAspect <\/code>trying to log system actions on startup, so I changed the pointcut configuration to look like this, in order to limit what was visible to aspectj:<\/p>\n\n\n\n<pre id=\"030d\" class=\"wp-block-code graf graf--pre graf-after--p\"><code>@Around(\"within(com.brianrook.medium.customer.controller. .*) \" +\n        \"&amp;&amp; within(com.brianrook.medium.customer.service. .*) \" +\n        \"&amp;&amp; within(com.brianrook.medium.customer.messaging. .*) \" +\n        \"&amp;&amp; within(com.brianrook.medium.customer.dao. .*) ) \")<\/code><\/pre>\n\n\n\n<p class=\"graf graf--p graf-after--pre\" id=\"5b41\">We can also startup the application locally if we add the following configuration to the application startup config:<\/p>\n\n\n\n<pre id=\"a3a9\" class=\"wp-block-code graf graf--pre graf-after--p\"><code>-Dspring.profiles.active=herokudb\n-Dspring.datasource.username=&lt;db username&gt;\n-Dspring.datasource.password=&lt;db password&gt;\n-Dspring.rabbitmq.username=&lt;cloudamqp username&gt;\n-Dspring.rabbitmq.password=&lt;cloudamqp password&gt;<\/code><\/pre>\n\n\n\n<p class=\"graf graf--p graf-after--pre\" id=\"e7ad\">If we save a customer, we should be able to see a message published in the cloudamqp manager console.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2021\/02\/1PYJQ6b60eZ2OmiluC3yhkg.png?w=960\" alt=\"\" data-recalc-dims=\"1\"\/><\/figure>\n\n\n\n<h3 class=\"graf graf--h3 graf-after--figure wp-block-heading\" id=\"54be\">Kubernetes Configuration<\/h3>\n\n\n\n<p class=\"graf graf--p graf-after--h3\" id=\"e5df\">This configuration is only valid for running locally for tests though. We need to configure our running application. We can do that by adding to our helm <code class=\"markup--code markup--p-code\">values.yaml<\/code> file and uploading another secrets file.<\/p>\n\n\n\n<p class=\"graf graf--p graf-after--p\" id=\"474b\">values.yaml<\/p>\n\n\n\n<pre id=\"30c1\" class=\"wp-block-code graf graf--pre graf-after--p\"><code>...<\/code><\/pre>\n\n\n\n<pre id=\"8836\" class=\"wp-block-code graf graf--pre graf-after--pre\"><code>content: |-\n  spring:<\/code><\/pre>\n\n\n\n<pre id=\"0623\" class=\"wp-block-code graf graf--pre graf-after--pre\"><code>...<\/code><\/pre>\n\n\n\n<pre id=\"d7d7\" class=\"wp-block-code graf graf--pre graf-after--pre\"><code>    cloud:\n      stream:\n        bindings:\n          output:\n            destination: queue.customer.create\n            content-type: application\/json\n    rabbitmq:\n      addresses: amqp:\/\/shrimp.rmq.cloudamqp.com\/c***j<\/code><\/pre>\n\n\n\n<pre id=\"baa9\" class=\"wp-block-code graf graf--pre graf-after--pre\"><code>...<\/code><\/pre>\n\n\n\n<pre id=\"18a5\" class=\"wp-block-code graf graf--pre graf-after--pre\"><code>secretsToEnv:<\/code><\/pre>\n\n\n\n<pre id=\"2a82\" class=\"wp-block-code graf graf--pre graf-after--pre\"><code>...<\/code><\/pre>\n\n\n\n<pre id=\"4f81\" class=\"wp-block-code graf graf--pre graf-after--pre\"><code>  - name: SPRING_RABBITMQ_PASSWORD\n    valueFrom:\n      secretKeyRef:\n        name: amqp-secrets\n        key: SPRING_RABBITMQ_PASSWORD\n  - name: SPRING_RABBITMQ_USERNAME\n    valueFrom:\n      secretKeyRef:\n        name: amqp-secrets\n        key: SPRING_RABBITMQ_USERNAME<\/code><\/pre>\n\n\n\n<p class=\"graf graf--p graf-after--pre\" id=\"9131\">Upload your secrets file<\/p>\n\n\n\n<pre id=\"4bd3\" class=\"wp-block-code graf graf--pre graf-after--p\"><code>kubectl create secret generic amqp-secrets --from-literal=SPRING_RABBITMQ_PASSWORD=&lt;cloud amqp password&gt; --from-literal=SPRING_RABBITMQ_USERNAME=&lt;cloud amqp user\/vhost&gt;<\/code><\/pre>\n\n\n\n<h3 class=\"graf graf--h3 graf-after--pre wp-block-heading\" id=\"17b7\">Build and&nbsp;Commit<\/h3>\n\n\n\n<pre id=\"3942\" class=\"wp-block-code graf graf--pre graf-after--h3\"><code>git checkout -b customer-updates\nmvn clean install\ngit add .\ngit commit -m \"new functionality and publishing\"\ngit push --set-upstream origin customer-updates\ngit checkout master\ngit merge customer-updates\ngit push<\/code><\/pre>\n\n\n\n<p class=\"graf graf--p graf-after--pre\" id=\"41a1\">Now lets let the build pipeline generate a new chart version and use the updated chart to deploy to minikube<\/p>\n\n\n\n<p class=\"graf graf--p graf-after--p\" id=\"faae\">After the build completes go to the helm chart registry and locate the latest version<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2021\/02\/1PYJQ6b60eZ2OmiluC3yhkg.png?w=960\" alt=\"\" data-recalc-dims=\"1\"\/><\/figure>\n\n\n\n<p class=\"graf graf--p graf-after--figure\" id=\"0a38\">In this case we want 5<\/p>\n\n\n\n<p class=\"graf graf--p graf-after--p\" id=\"d7a8\">take a look at helm to see what is currently deployed<\/p>\n\n\n\n<pre id=\"b9a3\" class=\"wp-block-code graf graf--pre graf-after--p\"><code>$ helm list\nNAME    NAMESPACE       REVISION        UPDATED                                 STATUS          CHART                   APP VERSION\nmedium  default         2               2020-04-04 13:56:58.2124564 -0600 MDT   deployed        medium-customer-3       0.0.1<\/code><\/pre>\n\n\n\n<p class=\"graf graf--p graf-after--pre\" id=\"87f6\">update the repositories<\/p>\n\n\n\n<pre id=\"b090\" class=\"wp-block-code graf graf--pre graf-after--p\"><code>helm repo update<\/code><\/pre>\n\n\n\n<p class=\"graf graf--p graf-after--pre\" id=\"46e8\">now list our repo contents<\/p>\n\n\n\n<pre id=\"1ba3\" class=\"wp-block-code graf graf--pre graf-after--p\"><code>$ helm search repo codefresh\nNAME                            CHART VERSION   APP VERSION     DESCRIPTION\ncodefresh\/medium-customer       5               0.0.1           A Helm chart for Kubernetes<\/code><\/pre>\n\n\n\n<p class=\"graf graf--p graf-after--pre\" id=\"3e0e\">we can see that the chart versions match, so we pulled down the latest built version. Lets deploy it.<\/p>\n\n\n\n<pre id=\"a30b\" class=\"wp-block-code graf graf--pre graf-after--p\"><code>helm upgrade medium codefresh\/medium-customer --version=5<\/code><\/pre>\n\n\n\n<p class=\"graf graf--p graf-after--pre\" id=\"86eb\">we should be able to verify any of the new functionality we added<\/p>\n\n\n\n<pre id=\"7cd2\" class=\"wp-block-code graf graf--pre graf-after--p\"><code>GET \/customer\/all HTTP\/1.1\nHost: 172.17.144.73:30001\nContent-Type: application\/json\nContent-Type: text\/plain<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<div class=\"entry-summary\">\nIn order publish messages, we need a message broker and add some&hellip;\n<\/div>\n<div class=\"link-more\"><a href=\"https:\/\/bullyrooks.com\/index.php\/2020\/03\/30\/simple-spring-boot-service-to-kubernetes-application-step-15-34e1bba8351b\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &ldquo;Messaging and Event Driven Design&rdquo;<\/span>&hellip;<\/a><\/div>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[41],"tags":[94,95,90,29,79,80,50,91,93,92],"course":[40],"class_list":["post-829","post","type-post","status-publish","format-standard","hentry","category-software-development","tag-amqp","tag-cloudamqp","tag-event-driven-architecture","tag-git","tag-helm","tag-kubernetes","tag-maven","tag-messaging","tag-pubsub","tag-rabbitmq","course-spring-with-kubernetes","entry"],"jetpack_featured_media_url":"","jetpack-related-posts":[{"id":1387,"url":"https:\/\/bullyrooks.com\/index.php\/2022\/03\/08\/kube-cloud-pt6-provider-contract-test-for-rest-endpoints\/","url_meta":{"origin":829,"position":0},"title":"Kube Cloud Pt6 | Provider Contract Test for REST Endpoints","author":"Bullyrook","date":"March 8, 2022","format":false,"excerpt":"Now lets move over to message-generator repo and create a new branch git checkout -b provider-test Pom Updates for Dependencies Update the pom.xml to pull in both the provider test library and the plugin ... <pact.version>4.3.5<\/pact.version> <maven-failsafe-plugin.version>3.0.0-M5<\/maven-failsafe-plugin.version> <maven-surefire-plugin.version>3.0.0-M5<\/maven-surefire-plugin.version> <pact.maven.plugin.version>4.3.5<\/pact.maven.plugin.version> <\/properties> ... <profiles> <profile> <id>contract<\/id> <build> <plugins> <plugin> <artifactId>maven-surefire-plugin<\/artifactId> <version>${maven-surefire-plugin.version}<\/version> <configuration>\u2026","rel":"","context":"In &quot;Software Development&quot;","block_context":{"text":"Software Development","link":"https:\/\/bullyrooks.com\/index.php\/category\/software-development\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/03\/image-10.png?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":1374,"url":"https:\/\/bullyrooks.com\/index.php\/2022\/03\/08\/kube-cloud-pt6-contract-testing\/","url_meta":{"origin":829,"position":1},"title":"Kube Cloud Pt6 | Contract Testing","author":"Bullyrook","date":"March 8, 2022","format":false,"excerpt":"Contract testing may be the most misunderstood and overlooked concept in distributed software development. As we're developing microservices we're going to need to do some service governance to make sure that service versions are compatible with each other. This can normally be managed with a conversation between teams developing in\u2026","rel":"","context":"In &quot;Software Development&quot;","block_context":{"text":"Software Development","link":"https:\/\/bullyrooks.com\/index.php\/category\/software-development\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1377,"url":"https:\/\/bullyrooks.com\/index.php\/2022\/03\/08\/kube-cloud-pt6-consumer-contract-tests-for-rest-endpoints\/","url_meta":{"origin":829,"position":2},"title":"Kube Cloud Pt6 | Consumer Contract Tests for REST Endpoints","author":"Bullyrook","date":"March 8, 2022","format":false,"excerpt":"Let's start with cloud-application, create a new branch git checkout -b client-contract Lets add the necessary dependencies to our pom.xml <pact.version>4.0.10<\/pact.version> <pact.provider.maven.plugin>4.3.5<\/pact.provider.maven.plugin> <\/properties> ... <!-- Contract Testing --> <dependency> <groupId>au.com.dius<\/groupId> <artifactId>pact-jvm-consumer-junit5<\/artifactId> <version>${pact.version}<\/version> <scope>test<\/scope> <\/dependency> ... <plugin> <groupId>au.com.dius.pact.provider<\/groupId> <artifactId>maven<\/artifactId> <version${pact.provider.maven.plugin}<\/version> <configuration> <pactBrokerUrl>${env.PACTFLOW_URL}<\/pactBrokerUrl> <pactBrokerToken>${env.PACTFLOW_TOKEN}<\/pactBrokerToken> <projectVersion>${env.PACT_PUBLISH_CONSUMER_VERSION}<\/projectVersion> <pactBrokerAuthenticationScheme>Bearer<\/pactBrokerAuthenticationScheme> <\/configuration> <\/plugin> Pact is mostly a\u2026","rel":"","context":"In &quot;Software Development&quot;","block_context":{"text":"Software Development","link":"https:\/\/bullyrooks.com\/index.php\/category\/software-development\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/03\/Screen-Shot-2022-03-02-at-2.04.53-PM.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/03\/Screen-Shot-2022-03-02-at-2.04.53-PM.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/03\/Screen-Shot-2022-03-02-at-2.04.53-PM.png?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/03\/Screen-Shot-2022-03-02-at-2.04.53-PM.png?resize=1050%2C600&ssl=1 3x, https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/03\/Screen-Shot-2022-03-02-at-2.04.53-PM.png?resize=1400%2C800&ssl=1 4x"},"classes":[]},{"id":1333,"url":"https:\/\/bullyrooks.com\/index.php\/2022\/02\/27\/kube-cloud-pt5-create-a-consumer-service\/","url_meta":{"origin":829,"position":3},"title":"Kube Cloud Pt5 | Create a Consumer Service","author":"Bullyrook","date":"February 27, 2022","format":false,"excerpt":"In this course we're going to migrate the repository storage function out of cloud-application and migrate it into a new service called message-repository. Although this is a relatively minor change in behavior (in exchange for a significant effort), there are some real world benefits that this example will provide cloud-application\u2026","rel":"","context":"In &quot;Software Development&quot;","block_context":{"text":"Software Development","link":"https:\/\/bullyrooks.com\/index.php\/category\/software-development\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/02\/pg1.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/02\/pg1.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/02\/pg1.png?resize=700%2C400&ssl=1 2x"},"classes":[]},{"id":1339,"url":"https:\/\/bullyrooks.com\/index.php\/2022\/02\/27\/kube-cloud-pt5-create-an-event-publisher\/","url_meta":{"origin":829,"position":4},"title":"Kube Cloud Pt5 | Create an Event Publisher","author":"Bullyrook","date":"February 27, 2022","format":false,"excerpt":"We're going to be updating cloud-application to remove the mongodb repository logic and replace it with an event publisher. Create a new branch from main git checkout -b migrate Update the pom.xml first, remove the mongodb dependencies <dependency> <groupId>org.springframework.boot<\/groupId> <artifactId>spring-boot-starter-data-mongodb<\/artifactId> <\/dependency> ... <dependency> <groupId>org.testcontainers<\/groupId> <artifactId>mongodb<\/artifactId> <version>1.16.3<\/version> <scope>test<\/scope> <\/dependency> and add\u2026","rel":"","context":"In &quot;Software Development&quot;","block_context":{"text":"Software Development","link":"https:\/\/bullyrooks.com\/index.php\/category\/software-development\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/02\/image-39.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/02\/image-39.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/02\/image-39.png?resize=700%2C400&ssl=1 2x"},"classes":[]},{"id":1356,"url":"https:\/\/bullyrooks.com\/index.php\/2022\/02\/27\/kube-cloud-pt5-create-an-event-consumer\/","url_meta":{"origin":829,"position":5},"title":"Kube Cloud Pt5 | Create an Event Consumer","author":"Bullyrook","date":"February 27, 2022","format":false,"excerpt":"Now that we've got messages being published to kafka, we are going to need to build our consumer that receives those events and stores them into the mongo database. Go ahead and create a new repository called message-repository according to the microservice startup course here. This is the pom.xml that\u2026","rel":"","context":"In &quot;Software Development&quot;","block_context":{"text":"Software Development","link":"https:\/\/bullyrooks.com\/index.php\/category\/software-development\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/02\/image-49.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/02\/image-49.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/bullyrooks.com\/wp-content\/uploads\/2022\/02\/image-49.png?resize=700%2C400&ssl=1 2x"},"classes":[]}],"_links":{"self":[{"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/posts\/829","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/comments?post=829"}],"version-history":[{"count":3,"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/posts\/829\/revisions"}],"predecessor-version":[{"id":905,"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/posts\/829\/revisions\/905"}],"wp:attachment":[{"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/media?parent=829"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/categories?post=829"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/tags?post=829"},{"taxonomy":"course","embeddable":true,"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/course?post=829"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}