Этот проект показывает систему отслеживания местоположения курьера в реальном времени, похожую на то, как это реализовано в Zomato или Swiggy, и построенную на Spring Boot и Apache Kafka.
👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
GitHub
GitHub - syedsameerpasha/Apache-Kafka-with-Spring-Boot: This project demonstrates a real-time delivery location tracking system…
This project demonstrates a real-time delivery location tracking system similar to Zomato/Swiggy, built using Spring Boot and Apache Kafka. - syedsameerpasha/Apache-Kafka-with-Spring-Boot
🤣4🌚3❤2💊1
Когда всё живёт в одной базе данных, с транзакциями всё просто.
BEGIN → COMMIT → ROLLBACK.
Но в распределённых системах всё резко усложняется.
В чём реальная проблема ???
В распределённых системах нельзя сделать одну транзакцию на всё сразу по нескольким причинам:
- несколько сервисов
- несколько баз данных
- множество возможных отказов
Классического rollback больше не существует.
И тут появляется паттерн Saga.
Saga это последовательность локальных транзакций, которые координируются между собой.
Каждый шаг:
- выполняет своё изменение
- фиксируется
- и определяет, как себя компенсировать, если дальше что-то пойдёт не так
Глобальной транзакции нет.
Есть eventual consistency.
Простой пример » Создание заказа может включать:
1. Создать заказ
2. Зарезервировать товар
3. Провести оплату
Если на шаге 3 происходит сбой, глобального rollback нет.
Выполняются компенсирующие действия:
- освободить резерв
- пометить заказ как отменённый
Это и есть Saga.
Два способа реализации Saga -
Хореография:
- сервисы реагируют на события
- центрального координатора нет
- слабая связность
- сложнее проследить общий поток
Оркестрация:
- есть компонент-координатор
- поток шагов явно описан
- проще рассуждать о логике
- выше связность
Частая ошибка » Считать, что Saga — это замена ACID-транзакциям.
Это не так.
Saga меняет сам контракт:
- допускаются промежуточные состояния
- компенсации проектируются явно
- принимается факт, что система может упасть на середине процесса
Когда Saga действительно имеет смысл
- долгоживущие процессы
- несколько сервисов
- реальные побочные эффекты: платежи, доставки, резервы
- ситуации, где технического rollback не существует
Если всё находится в одной базе данных, Saga не нужна. Здесь легко уйти в оверинжиниринг.
Ключевая мысль:
Явная сложность лучше, чем спрятанная за предположениями, которые больше не работают.
В распределённых системах сбои — это не исключение, а часть нормального потока.
Паттерн Saga не избавляет от всех проблем,
но помогает избежать беспорядка.
А в продакшене это уже большая разница.☃️
👉 Java Portal
BEGIN → COMMIT → ROLLBACK.
Но в распределённых системах всё резко усложняется.
В чём реальная проблема ???
В распределённых системах нельзя сделать одну транзакцию на всё сразу по нескольким причинам:
- несколько сервисов
- несколько баз данных
- множество возможных отказов
Классического rollback больше не существует.
И тут появляется паттерн Saga.
Saga это последовательность локальных транзакций, которые координируются между собой.
Каждый шаг:
- выполняет своё изменение
- фиксируется
- и определяет, как себя компенсировать, если дальше что-то пойдёт не так
Глобальной транзакции нет.
Есть eventual consistency.
Простой пример » Создание заказа может включать:
1. Создать заказ
2. Зарезервировать товар
3. Провести оплату
Если на шаге 3 происходит сбой, глобального rollback нет.
Выполняются компенсирующие действия:
- освободить резерв
- пометить заказ как отменённый
Это и есть Saga.
Два способа реализации Saga -
Хореография:
- сервисы реагируют на события
- центрального координатора нет
- слабая связность
- сложнее проследить общий поток
Оркестрация:
- есть компонент-координатор
- поток шагов явно описан
- проще рассуждать о логике
- выше связность
Ни один подход не является универсально лучшим.
Всё зависит от системы и контекста.
Частая ошибка » Считать, что Saga — это замена ACID-транзакциям.
Это не так.
Saga меняет сам контракт:
- допускаются промежуточные состояния
- компенсации проектируются явно
- принимается факт, что система может упасть на середине процесса
Когда Saga действительно имеет смысл
- долгоживущие процессы
- несколько сервисов
- реальные побочные эффекты: платежи, доставки, резервы
- ситуации, где технического rollback не существует
Если всё находится в одной базе данных, Saga не нужна. Здесь легко уйти в оверинжиниринг.
Ключевая мысль:
Saga не убирает сложность.
Она делает её явной.
Явная сложность лучше, чем спрятанная за предположениями, которые больше не работают.
В распределённых системах сбои — это не исключение, а часть нормального потока.
Паттерн Saga не избавляет от всех проблем,
но помогает избежать беспорядка.
А в продакшене это уже большая разница.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤1
Java Tip: Начиная с Java 14 можно использовать record для создания компактных неизменяемых объектов, которые просто переносят данные.
» Они короче обычных POJO
» У них из коробки есть equals(), hashCode() и toString()
» По умолчанию они неизменяемые
Классический POJO:
Вместо этого можно создать record:
Смысл ровно тот же, но без бойлерплейта.
👉 Java Portal
» Они короче обычных POJO
» У них из коробки есть equals(), hashCode() и toString()
» По умолчанию они неизменяемые
Классический POJO:
public class Book {
private final String title;
private final int price;
public Book(String title, int price) {
this.title = title;
this.price = price;
}
// геттеры, toString, equals и hashCode
}Вместо этого можно создать record:
public record Book(String title, int price) {}Смысл ровно тот же, но без бойлерплейта.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍17
Когда ты уже не джун и даже не мидл, на собеседованиях по Java почти не задают вопросы в стиле «что такое HashMap». В ход идут сценарии из реальной жизни.
Разберём типичный кейс.
Твой сервис — оркестратор. Он дергает несколько downstream-сервисов, чтобы обработать запрос.
Один из них проблемный: медленный и периодически отвечает 503 Service Unavailable.
1. Как сделать сервис устойчивым к ненадёжному downstream
Первое, что здесь просится » Circuit Breaker.
Идея простая: если зависимый сервис начинает фейлиться, мы перестаём его дёргать, чтобы:
- не тратить ресурсы,
- не увеличивать латентность,
- не убивать весь сервис каскадными таймаутами.
Реализация с Resilience4j:
Подключаем зависимость и оборачиваем вызов проблемного сервиса в CircuitBreaker.
Ключевые состояния:
Всё нормально. Запросы проходят. Ошибки считаются.
Порог ошибок превышен. Все вызовы сразу фейлятся, downstream даже не вызывается.
Пробный режим. Ограниченное число запросов, чтобы проверить — ожил сервис или нет.
Пример:
Конфиг обычно задаётся через application.yml:
- процент ошибок
- sliding window
- waitDurationInOpenState
- permittedNumberOfCallsInHalfOpenState
2. Что делать, когда circuit открыт (fallback)
Тут нет универсального ответа » зависит от бизнеса.
Типовые варианты:
🔹 Кэш
Если данные не критичны к свежести:
- Redis
- локальный cache
- stale-данные лучше, чем 503
🔹 Дефолтный ответ
Если можно вернуть «безопасное» значение:
- пустой список
- available = false
- статус UNKNOWN
🔹 Очередь
Если запрос важен, но не срочный:
- кладём событие в Kafka / Rabbit
- обрабатываем асинхронно
- отвечаем клиенту 202 Accepted
На практике часто комбинируют:
кэш + деградация функциональности.
3. Глобальная обработка ошибок через
Чтобы не размазывать try/catch по всему коду, делаем централизованный обработчик.
Пример бизнес-исключения
Глобальный handler
Плюсы подхода:
- чистые контроллеры
- единый формат ошибок
- нормальная мапа бизнес-ошибок на HTTP-статусы
Итог
На таком вопросе проверяют не знание аннотаций, а мышление:
- понимаешь ли ты отказоустойчивость
- умеешь ли деградировать сервис
- разделяешь ли бизнес-ошибки и технические фейлы
Это уже разговор не про «Java», а про архитектуру продакшн-сервисов
👉 Java Portal
Разберём типичный кейс.
Твой сервис — оркестратор. Он дергает несколько downstream-сервисов, чтобы обработать запрос.
Один из них проблемный: медленный и периодически отвечает 503 Service Unavailable.
1. Как сделать сервис устойчивым к ненадёжному downstream
Первое, что здесь просится » Circuit Breaker.
Идея простая: если зависимый сервис начинает фейлиться, мы перестаём его дёргать, чтобы:
- не тратить ресурсы,
- не увеличивать латентность,
- не убивать весь сервис каскадными таймаутами.
Реализация с Resilience4j:
Подключаем зависимость и оборачиваем вызов проблемного сервиса в CircuitBreaker.
Ключевые состояния:
Всё нормально. Запросы проходят. Ошибки считаются.
Порог ошибок превышен. Все вызовы сразу фейлятся, downstream даже не вызывается.
Пробный режим. Ограниченное число запросов, чтобы проверить — ожил сервис или нет.
Пример:
@CircuitBreaker(name = "inventoryService", fallbackMethod = "inventoryFallback")
public InventoryResponse getInventory(String productId) {
return inventoryClient.getInventory(productId);
}
Конфиг обычно задаётся через application.yml:
- процент ошибок
- sliding window
- waitDurationInOpenState
- permittedNumberOfCallsInHalfOpenState
2. Что делать, когда circuit открыт (fallback)
Тут нет универсального ответа » зависит от бизнеса.
Типовые варианты:
Если данные не критичны к свежести:
- Redis
- локальный cache
- stale-данные лучше, чем 503
private InventoryResponse inventoryFallback(String productId, Throwable ex) {
return cacheService.getInventory(productId);
}Если можно вернуть «безопасное» значение:
- пустой список
- available = false
- статус UNKNOWN
Если запрос важен, но не срочный:
- кладём событие в Kafka / Rabbit
- обрабатываем асинхронно
- отвечаем клиенту 202 Accepted
На практике часто комбинируют:
кэш + деградация функциональности.
3. Глобальная обработка ошибок через
@RestControllerAdviceЧтобы не размазывать try/catch по всему коду, делаем централизованный обработчик.
Пример бизнес-исключения
public class ProductNotFoundException extends RuntimeException {
public ProductNotFoundException(String id) {
super("Product not found: " + id);
}
}Глобальный handler
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ProductNotFoundException.class)
public ResponseEntity<ErrorResponse> handleProductNotFound(ProductNotFoundException ex) {
ErrorResponse error = new ErrorResponse(
"PRODUCT_NOT_FOUND",
ex.getMessage()
);
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
}
}
JSON-ответ
{
"code": "PRODUCT_NOT_FOUND",
"message": "Product not found: 123"
}
Плюсы подхода:
- чистые контроллеры
- единый формат ошибок
- нормальная мапа бизнес-ошибок на HTTP-статусы
Итог
На таком вопросе проверяют не знание аннотаций, а мышление:
- понимаешь ли ты отказоустойчивость
- умеешь ли деградировать сервис
- разделяешь ли бизнес-ошибки и технические фейлы
Это уже разговор не про «Java», а про архитектуру продакшн-сервисов
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10❤3
Spring Boot наконец получил нативную поддержку gRPC
Забудьте о сторонних стартерах и костылях — Spring gRPC 1.0 GA уже здесь. Теперь можно строить высокопроизводительные RPC-сервисы с Protocol Buffers прямо из коробки, без плясок с бубном.
👉 Java Portal
Забудьте о сторонних стартерах и костылях — Spring gRPC 1.0 GA уже здесь. Теперь можно строить высокопроизводительные RPC-сервисы с Protocol Buffers прямо из коробки, без плясок с бубном.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤9
Kubernetes-совет:
Java-приложения обычно требуют больше CPU на старте, чем во время обычной работы☕️
Эта политика Kyverno:
- отслеживает момент завершения старта pod’а
- обновляет ресурсы pod’а прямо на месте
- снижает CPU-лимиты после старта
Итог: более быстрый запуск и меньшие затраты
Вот моя статья об этом
👉 Java Portal
Java-приложения обычно требуют больше CPU на старте, чем во время обычной работы
Эта политика Kyverno:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: resize-pod-policy
spec:
mutateExistingOnPolicyUpdate: false
rules:
- name: resize-pod-policy
match:
any:
- resources:
kinds:
- Pod/status
- Pod
preconditions:
all:
- key: "{{request.object.status.containerStatuses[0].ready}}"
operator: Equals
value: true
mutate:
targets:
- apiVersion: v1
kind: Pod.resize
name: "{{request.object.iss.onetadata.name}}"
patchStrategicMerge:
spec:
containers:
- (name): sample-app-on-kubernetes
resources:
limits:
cpu: 0.5
- отслеживает момент завершения старта pod’а
- обновляет ресурсы pod’а прямо на месте
- снижает CPU-лимиты после старта
Итог: более быстрый запуск и меньшие затраты
Вот моя статья об этом
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔6❤1👍1
Java-совет: избегайте глубоко вложенных if/else.
Используйте guard clauses (ранние выходы из метода) вместо этого.
👉 Java Portal
Используйте guard clauses (ранние выходы из метода) вместо этого.
❌ Вложенные if-else:
public void processOrder(Order order) {
if (order != null) {
if (order.isPaid()) {
if (order.getItems().size() > 0) {
// Обработка заказа
System.out.println("Заказ обработан");
} else {
System.out.println("В заказе нет позиций");
}
} else {
System.out.println("Заказ не оплачен");
}
} else {
System.out.println("Заказ равен null");
}
}
✅ Использование guard clauses (читается проще):
public void processOrder(Order order) {
if (order == null) {
System.out.println("Заказ равен null");
return;
}
if (!order.isPaid()) {
System.out.println("Заказ не оплачен");
return;
}
if (order.getItems().isEmpty()) {
System.out.println("В заказе нет позиций");
return;
}
// Обработка заказа
System.out.println("Заказ обработан");
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9❤4
24 декабря(уже завтра!) в 19:00 по мск приходи онлайн на открытое собеседование, чтобы посмотреть на настоящее интервью на Middle Java-разработчика.
Как это будет:
📂 Сергей Чамкин, старший разработчик из Uzum, ex-WildBerries, будет задавать реальные вопросы и задачи разработчику-добровольцу
📂 Cергей будет комментировать каждый ответ респондента, чтобы дать понять чего от вас ожидает собеседующий на интервью
📂 В конце можно будет задать любой вопрос Сергею
Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для Java-разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы.
Переходи в нашего бота, чтобы получить ссылку на эфир → @shortcut_sh_bot
Реклама.
О рекламодателе.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1
Создаём первый Minecraft мод и подробно разбираем Mixin. Просто и понятно
Эта статья была написана из-за отсутствия адекватных русскоязычных руководств по моддингу, особенно для новых версий Minecraft. То, что описано в статье, будет применимо для таких загрузчиков модов, как Fabric и Forge, а также для реализации различных функций.
👉 Java Portal
Эта статья была написана из-за отсутствия адекватных русскоязычных руководств по моддингу, особенно для новых версий Minecraft. То, что описано в статье, будет применимо для таких загрузчиков модов, как Fabric и Forge, а также для реализации различных функций.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤11👍1