Kayıtlar

Transactional Outbox Pattern

Resim
Dual Write Problem The dual write problem means it’s hard to keep different data sources working together when you write or save things. We need to make sure that all the writes are done correctly and the same in all places. If one write operation fails or only partially succeeds, it can lead to data integrity issues. Dual Write Problem Diagram The Transactional Outbox pattern helps solve the Dual Write Problem. It adds a middle step to keep writing actions separate. How the Pattern Works Let’s assume that we also need to send an event to the notification service when a customer is created. It doesn’t immediately tell another service. Instead, it puts the important details in a special table called an outbox table. Customer savedCustomer = customerRepository.save( new Customer (customerDto.username(), customerDto.email())); //customerProducerService.sendCustomerCreatedEvent(savedCustomer); OutboxEvent outboxEvent = new OutboxEvent (); outboxEvent.setEventPayloa...

Cucumber Implementation in Spring Boot

Resim
  Cucumber is an open-source testing tool that supports Behavior-Driven Development (BDD) by facilitating the creation, execution, and automation of BDD-style tests. It works based on the Gherkin Domain Specific Language (DSL). This simple but powerful syntax of Gherkin lets developers and testers write complex tests while makes it understandable even for non-technical users. Key Concepts Given-When-Then: This is a common structure used in feature files. “Given” sets up the initial state, “When” represents the action, and “Then” defines the expected outcome. Feature: Describes the high-level functionality of your application. Scenario: Represents a specific test case within a feature. Background: Contains steps that are common to all scenarios within a feature. Scenario Outline: It is used to define a template for a scenario with placeholders for inputs or data. The placeholders are defined using angle brackets ( <> ). Examples: It is used to provide concrete ...

Kafka Message Key Hashing

Resim
 In Kafka each event message contains an optional key and a value. key == null : messages are distributed evenly across partitions in a topic (a round-robin strategy). key != null : All messages that share same key will always be sent and stored in the same partition. ** A key can be anything to identify a message (a string, numeric value, binary value etc.). Key Hashing is the process of determining the mapping of a key to a partition. A Kafka partitioner is a code logic that takes a record and determines to which partition to send it into. ** In the default Kafka partitioner, the keys are hashed using murmur2 algorithm ( murmur hash ). targetPartition = Math.abs(Utils.murmur2(keyBytes) % (numPartitions - 1)) Example Flow: Message 1 : account_id = 12345 hash(12345) % 2 might result in 0 -> Partition 0 Message 2 : account_id = 67890 hash(67890) % 2 might result in 1 -> Partition 1 Message 3 : account_id = 12345 (same as Message 1) hash(12345) % 2 still results in...

SQL Indexing Best Practices

Before we show best practices, let’s look at how database indexes work. A database index is a type of data structure like an array or hash. Without any indexes our database has to scan every row in the table. What if this table had 20 million rows? Running a single query consume a lot of resources and if this table used by an application it could have thousand similar queries. The solution to this problem is to use indexes. We want to index the data is looked up most frequently. SELECT * FROM users WHERE city = 'Berlin' ORDER BY balance DESC ; CREATE INDEX city_idx ON users(city); SQL index is basically a shorted list with the values from one or more rows of a table and a pointer value that tells the database where to find. Indexes are automatically maintained by database engine. This means that whenever a DML operation is performed on the table, the same operation is done on each of the indexes. For queries that are going to be run frequently we can make th...

JUnit 5 Parameterized Tests

  JUnit 5 provides parameterized tests, which let you run a test multiple times with different arguments. This is especially useful when you want to test a function with various inputs without writing repetitive test cases. Basic Structure of a Parameterized Test To create a parameterized test, use the @ParameterizedTest annotation. You also need a source of parameters, which JUnit provides through different annotations like @ValueSource , @CsvSource , @CsvFileSource. ValueSource : Supplies a single array of primitive types or strings. @Service public class AccountValidationService { // Example rules: // - Account number must be 10 digits // - Must start with "ACC" public boolean validateAccountNumber (String accountNumber) { if (accountNumber == null ) { return false ; } if (!accountNumber.startsWith( "ACC" )) { return false ; } if (accountNumber.length() != 10 ) { ...

Spring Boot Actuator Configuration

Spring Boot Actuator is a set of tools that add monitoring and management features to your application. It exposes many endpoints that allow you to inspect Spring Boot application. For example, you can check the application’s health status, view metrics and manage beans directly. < dependency > < groupId > org.springframework.boot </ groupId > < artifactId > spring-boot-starter-actuator </ artifactId > </ dependency > Here are some of the important Actuator endpoints: /actuator/health : Shows the health status of the application. /actuator/metrics : Provides metrics like memory usage, CPU load, request count, etc. /actuator/beans : Lists all the beans in your application. /actuator/loggers : Allows you to view and change log levels for specific packages. /actuator/env : Exposes properties in the application’s environment. You can access these endpoints by running your application and navigating to http://localhost:8080/actuator . # Enable...

Graceful Shutdown in Kubernetes

Resim
In this article, you will learn how to prevent broken connections when a pod starts or shuts down. You will also learn how to shut down long-running tasks and connections gracefully. Rolling updates, as the name suggests, allow you to update your application in a gradual and controlled manner. This strategy ensures that your application remains available to users throughout the update process. Graceful shutdown is a critical aspect of rolling updates. When a pod is scheduled for termination, it must ensure it finishes processing requests and gracefully releases resources. Key features of the graceful shutdown include: Connection Draining: Incoming connections can complete their transactions before the pod terminates. This prevents abrupt service interruptions for clients. Resource Cleanup: Resources such as files, sockets, and database connections are released properly before the pod terminates. This prevents resource leaks and ensures efficient resource utilization. Gr...