Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@

<build>
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
<testSourceDirectory>src/test/kotlin</testSourceDirectory>
<testSourceDirectory>src/test/jvmTarget</testSourceDirectory>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
Expand Down
42 changes: 24 additions & 18 deletions src/main/kotlin/ru/quipy/apigateway/APIController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,19 @@ package ru.quipy.apigateway
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.web.bind.annotation.*
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController
import ru.quipy.common.utils.RateLimiter
import ru.quipy.orders.repository.OrderRepository
import ru.quipy.payments.logic.OrderPayer
import java.util.*
import java.util.UUID
import kotlin.random.Random

@RestController
class APIController {

class APIController(val rateLimiter: RateLimiter) {
val logger: Logger = LoggerFactory.getLogger(APIController::class.java)

@Autowired
Expand Down Expand Up @@ -49,26 +54,27 @@ class APIController {
)

enum class OrderStatus {
COLLECTING,
PAYMENT_IN_PROGRESS,
PAID,
COLLECTING, PAYMENT_IN_PROGRESS, PAID,
}

@PostMapping("/orders/{orderId}/payment")
fun payOrder(@PathVariable orderId: UUID, @RequestParam deadline: Long): PaymentSubmissionDto {
val paymentId = UUID.randomUUID()
val order = orderRepository.findById(orderId)?.let {
orderRepository.save(it.copy(status = OrderStatus.PAYMENT_IN_PROGRESS))
it
} ?: throw IllegalArgumentException("No such order $orderId")


val createdAt = orderPayer.processPayment(orderId, order.price, paymentId, deadline)
return PaymentSubmissionDto(createdAt, paymentId)
while (true) {
if (rateLimiter.tick()) {
val paymentId = UUID.randomUUID()
val order = orderRepository.findById(orderId)?.let {
orderRepository.save(it.copy(status = OrderStatus.PAYMENT_IN_PROGRESS))
it
} ?: throw IllegalArgumentException("No such order $orderId")
val createdAt = orderPayer.processPayment(orderId, order.price, paymentId, deadline)
return PaymentSubmissionDto(createdAt, paymentId)
}
}
}

private fun waitProgress() = Thread.sleep(Random.nextLong(1000, 2000))

class PaymentSubmissionDto(
val timestamp: Long,
val transactionId: UUID
val timestamp: Long, val transactionId: UUID
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ package ru.quipy.common.utils

import io.github.resilience4j.ratelimiter.RateLimiterConfig
import io.github.resilience4j.ratelimiter.RateLimiterRegistry
import kotlinx.coroutines.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.time.Duration
Expand Down
13 changes: 13 additions & 0 deletions src/main/kotlin/ru/quipy/config/ApiConfig.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package ru.quipy.config

import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import ru.quipy.common.utils.RateLimiter
import ru.quipy.common.utils.SlidingWindowRateLimiter
import java.time.Duration

@Configuration
class ApiConfig {
@Bean
fun getDefaultRateLimiter(): RateLimiter = SlidingWindowRateLimiter(8, Duration.ofSeconds(1))
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import ru.quipy.core.EventSourcingServiceFactory
import ru.quipy.payments.api.PaymentAggregate
import ru.quipy.payments.logic.PaymentAggregateState
import ru.quipy.streams.AggregateEventStreamManager
import java.util.*
import java.util.UUID


/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import org.springframework.stereotype.Service
import ru.quipy.apigateway.APIController.Order
import ru.quipy.streams.AggregateSubscriptionsManager
import java.time.Duration
import java.util.*
import java.util.UUID

@Service
class OrderRepository {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package ru.quipy.payments.api
import ru.quipy.core.annotations.DomainEvent
import ru.quipy.domain.Event
import java.time.Duration
import java.util.*
import java.util.UUID

const val PAYMENT_CREATED_EVENT = "PAYMENT_CREATED_EVENT"
const val PAYMENT_SUBMITTED_EVENT = "PAYMENT_SUBMITTED_EVENT"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import ru.quipy.core.EventSourcingService
import ru.quipy.payments.api.PaymentAggregate
import ru.quipy.payments.logic.*
import ru.quipy.payments.logic.PaymentAccountProperties
import ru.quipy.payments.logic.PaymentAggregateState
import ru.quipy.payments.logic.PaymentExternalSystemAdapter
import ru.quipy.payments.logic.PaymentExternalSystemAdapterImpl
import java.net.URI
import java.net.http.HttpClient
import java.net.http.HttpRequest
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import ru.quipy.payments.api.PaymentCreatedEvent
import ru.quipy.payments.api.PaymentProcessedEvent
import ru.quipy.payments.api.PaymentSubmittedEvent
import java.time.Duration
import java.util.*
import java.util.UUID


fun PaymentAggregateState.create(id: UUID, orderId: UUID, amount: Int): PaymentCreatedEvent {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import ru.quipy.payments.api.PaymentCreatedEvent
import ru.quipy.payments.api.PaymentProcessedEvent
import ru.quipy.payments.api.PaymentSubmittedEvent
import java.time.Duration
import java.util.*
import java.util.UUID
import java.util.concurrent.ConcurrentHashMap

class PaymentAggregateState : AggregateState<UUID, PaymentAggregate> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import ru.quipy.core.EventSourcingService
import ru.quipy.payments.api.PaymentAggregate
import java.net.SocketTimeoutException
import java.time.Duration
import java.util.*
import java.util.UUID


// Advice: always treat time as a Duration
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/ru/quipy/payments/logic/PaymentService.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package ru.quipy.payments.logic

import java.time.Duration
import java.util.*
import java.util.UUID

interface PaymentService {
/**
Expand Down
10 changes: 1 addition & 9 deletions src/main/kotlin/ru/quipy/payments/logic/PaymentServiceImpl.kt
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
package ru.quipy.payments.logic

import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import ru.quipy.common.utils.NamedThreadFactory
import ru.quipy.core.EventSourcingService
import ru.quipy.payments.api.PaymentAggregate
import java.time.Duration
import java.util.*
import java.util.concurrent.Executors
import java.util.concurrent.locks.ReentrantLock
import kotlin.concurrent.withLock
import java.util.UUID


@Service
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package ru.quipy.payments.subscribers

import jakarta.annotation.PostConstruct
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
Expand All @@ -9,10 +10,9 @@ import ru.quipy.payments.api.PaymentProcessedEvent
import ru.quipy.streams.AggregateSubscriptionsManager
import ru.quipy.streams.annotation.RetryConf
import ru.quipy.streams.annotation.RetryFailedStrategy
import java.util.*
import java.util.UUID
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.CopyOnWriteArrayList
import jakarta.annotation.PostConstruct

@Service
class PaymentTransactionsSubscriber {
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ management.endpoints.web.exposure.include=info,health,prometheus,metrics

payment.service-name=${PAYMENT_SERVICE_NAME}
payment.token=${PAYMENT_TOKEN}
payment.accounts=${PAYMENT_ACCOUNTS:acc-12,acc-20}
payment.accounts=${PAYMENT_ACCOUNTS:acc-3}
payment.hostPort=${PAYMENT_HOST:localhost}:${PAYMENT_PORT:1234}