Compare commits
No commits in common. "0ebd562be28e0fd4a39e9c880d3e920b5edb5079" and "22a3917d28dcb12c084214aec1e9f54fbc6c1683" have entirely different histories.
0ebd562be2
...
22a3917d28
26
.gitignore
vendored
@ -7,29 +7,3 @@
|
|||||||
/dozorova_alena_lab_2/ConsoleApp2/.vs
|
/dozorova_alena_lab_2/ConsoleApp2/.vs
|
||||||
/dozorova_alena_lab_2/ConsoleApp2/bin
|
/dozorova_alena_lab_2/ConsoleApp2/bin
|
||||||
/dozorova_alena_lab_2/ConsoleApp2/obj
|
/dozorova_alena_lab_2/ConsoleApp2/obj
|
||||||
/dozorova_alena_lab_3/PostService/.vs
|
|
||||||
/dozorova_alena_lab_3/WorkerService/.vs
|
|
||||||
/dozorova_alena_lab_4/Receive/bin
|
|
||||||
/dozorova_alena_lab_4/Receive/obj
|
|
||||||
/dozorova_alena_lab_4/Send/bin
|
|
||||||
/dozorova_alena_lab_4/Send/obj
|
|
||||||
/dozorova_alena_lab_4/EmitLog/.vs
|
|
||||||
/dozorova_alena_lab_4/EmitLog/obj
|
|
||||||
/dozorova_alena_lab_4/NewTask/.vs
|
|
||||||
/dozorova_alena_lab_4/NewTask/bin
|
|
||||||
/dozorova_alena_lab_4/NewTask/obj
|
|
||||||
/dozorova_alena_lab_4/ReceiveLogs/obj
|
|
||||||
/dozorova_alena_lab_4/Worker/.vs
|
|
||||||
/dozorova_alena_lab_4/Worker/bin
|
|
||||||
/dozorova_alena_lab_4/Worker/obj
|
|
||||||
/dozorova_alena_lab_4/EmitLog/bin
|
|
||||||
/dozorova_alena_lab_4/ReceiveLogs/.vs
|
|
||||||
/dozorova_alena_lab_4/ReceiveLogs/bin
|
|
||||||
/dozorova_alena_lab_4/ConsumerDelay/.vs
|
|
||||||
/dozorova_alena_lab_4/ConsumerDelay/obj
|
|
||||||
/dozorova_alena_lab_4/ConsumerDelay/Properties
|
|
||||||
/dozorova_alena_lab_4/ConsumerSimple/.vs
|
|
||||||
/dozorova_alena_lab_4/ConsumerSimple/obj
|
|
||||||
/dozorova_alena_lab_4/Publisher/.vs
|
|
||||||
/dozorova_alena_lab_4/Publisher/bin
|
|
||||||
/dozorova_alena_lab_4/Publisher/obj
|
|
||||||
|
2
bogdanov_dmitry_lab_2/.gitignore
vendored
@ -1,2 +0,0 @@
|
|||||||
data/
|
|
||||||
result/
|
|
@ -1,41 +0,0 @@
|
|||||||
# Лабораторная работа №2
|
|
||||||
|
|
||||||
## Богданов Дмитрий ПИбд-42
|
|
||||||
|
|
||||||
### Для выполнения была проделана следующая работа:
|
|
||||||
Были написаны и развернуты 3 сервиса: генератор файлов, 2 приложения для работы с этими файлами по вариантам 2 и 1 соответственно:
|
|
||||||
|
|
||||||
Вариант 2 (для первого приложения):
|
|
||||||
|
|
||||||
```Формирует файл /var/result/data.txt из первых строк всех файлов каталога /var/data.```
|
|
||||||
|
|
||||||
Вариант 1 (для второго приложения):
|
|
||||||
|
|
||||||
```Ищет набольшее число из файла /var/data/data.txt и сохраняет его вторую степень в /var/result/result.txt.```
|
|
||||||
|
|
||||||
Приложения работают совместно, используя общий монтированный том для записи и получения информации:
|
|
||||||
```
|
|
||||||
volumes:
|
|
||||||
- ./data:/var/data
|
|
||||||
```
|
|
||||||
```
|
|
||||||
volumes:
|
|
||||||
- ./data:/var/data
|
|
||||||
- ./result:/var/result
|
|
||||||
```
|
|
||||||
```
|
|
||||||
volumes:
|
|
||||||
- ./result:/var/result
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
### Запуск лабораторной:
|
|
||||||
Необходимо перейти в папку с файлом docker-compose.yaml и ввести следующую команду:
|
|
||||||
```
|
|
||||||
docker compose up --build
|
|
||||||
```
|
|
||||||
Сервис генератора сгенерирует папки data и result, где будут сгенерированы входные файлы и файл-результат их обработки соответственно.
|
|
||||||
|
|
||||||
## Видео с результатом запуска:
|
|
||||||
|
|
||||||
Видео-демонстрацию работы можно посмотреть по данной [ссылке](https://drive.google.com/file/d/1CmVZjJuMStqNFFKbsMLjw4ihTiMnR7it/view).
|
|
@ -1,7 +0,0 @@
|
|||||||
FROM python:latest
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
COPY app.py /app/
|
|
||||||
|
|
||||||
CMD ["python", "app.py"]
|
|
@ -1,30 +0,0 @@
|
|||||||
import os
|
|
||||||
|
|
||||||
# Вариант 2 - Формирует файл /var/result/data.txt из первых строк всех файлов каталога /var/data.
|
|
||||||
def solve(dir_files, dir_result, filename_result):
|
|
||||||
# Получаем список файлов в директории
|
|
||||||
filenames = os.listdir(dir_files)
|
|
||||||
result = ''
|
|
||||||
# Проходим через каждый файл
|
|
||||||
for filename in filenames:
|
|
||||||
filepath = os.path.join(dir_files, filename)
|
|
||||||
file = open(filepath, "r")
|
|
||||||
# Читаем первую строку, добавляем к результату
|
|
||||||
result += f"{file.readline()}"
|
|
||||||
file.close()
|
|
||||||
|
|
||||||
# Если директории для сохранения результата нет - создаём
|
|
||||||
if not os.path.exists(dir_result):
|
|
||||||
os.makedirs(dir_result)
|
|
||||||
# Если директория с результатом не пустая - завершаем работу
|
|
||||||
if os.listdir(dir_result):
|
|
||||||
return
|
|
||||||
# Пишем результат в файл
|
|
||||||
filepath_result = os.path.join(dir_result, filename_result)
|
|
||||||
result_file = open(filepath_result, "w")
|
|
||||||
result_file.write(result)
|
|
||||||
print(f"Результат записан в файл {filepath_result}")
|
|
||||||
result_file.close()
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
solve('/var/data', '/var/result', 'data.txt')
|
|
@ -1,7 +0,0 @@
|
|||||||
FROM python:latest
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
COPY app.py /app/
|
|
||||||
|
|
||||||
CMD ["python", "app.py"]
|
|
@ -1,21 +0,0 @@
|
|||||||
import os
|
|
||||||
|
|
||||||
# Вариант 1 - Ищет набольшее число из файла /var/data/data.txt и сохраняет его вторую степень в /var/result/result.txt.
|
|
||||||
def solve(dir_input, dir_result, filename_result):
|
|
||||||
file_input = open(os.path.join(dir_input, 'data.txt'))
|
|
||||||
# Считываем все числа из файла
|
|
||||||
inputs = [int(line) for line in file_input.readlines()]
|
|
||||||
if inputs:
|
|
||||||
# Максимальное число
|
|
||||||
max_num = max(inputs)
|
|
||||||
print(f"Наибольшее число: {max_num}")
|
|
||||||
# Возводим во 2 степень
|
|
||||||
result = max(inputs) ** 2
|
|
||||||
file_result = open(os.path.join(dir_result, filename_result), "w")
|
|
||||||
# Пишем результат в файл
|
|
||||||
file_result.write(str(result))
|
|
||||||
print(f"Получен результат {result}")
|
|
||||||
file_result.close()
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
solve("/var/result", '/var/result', 'result.txt')
|
|
@ -1,7 +0,0 @@
|
|||||||
FROM python:latest
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
COPY generator.py /app/
|
|
||||||
|
|
||||||
CMD ["python", "generate_files.py"]
|
|
@ -1,30 +0,0 @@
|
|||||||
import os
|
|
||||||
import random as rnd
|
|
||||||
import string
|
|
||||||
|
|
||||||
# Генератор названий файлов
|
|
||||||
def generate_filename(l):
|
|
||||||
return ''.join(rnd.choices(string.ascii_lowercase + string.digits, k=l)) + '.txt'
|
|
||||||
|
|
||||||
def generate_files(dir, num_files, num_lines):
|
|
||||||
# Если директории для сохранения файлов нет - создаём
|
|
||||||
if not os.path.exists(dir):
|
|
||||||
os.makedirs(dir)
|
|
||||||
|
|
||||||
# Если директория для сохранения файлов не пустая - завершаем работу
|
|
||||||
if os.listdir(dir):
|
|
||||||
return
|
|
||||||
|
|
||||||
# Создание файлов
|
|
||||||
for i in range(num_files):
|
|
||||||
filename = generate_filename(20)
|
|
||||||
filepath = os.path.join(dir, filename)
|
|
||||||
|
|
||||||
file = open(filepath, "w")
|
|
||||||
# Запись строк в файл
|
|
||||||
for j in range(num_lines):
|
|
||||||
file.write(f"{rnd.randint(-1000, 1000)}\n")
|
|
||||||
file.close()
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
generate_files('/var/data', 50, 50)
|
|
@ -1,27 +0,0 @@
|
|||||||
services:
|
|
||||||
# Генератор файлов
|
|
||||||
generator:
|
|
||||||
build:
|
|
||||||
context: ./app-generator # Путь к контексту (докер файл + скрипт)
|
|
||||||
volumes:
|
|
||||||
- ./data:/var/data # Папка контейнера : папка локальная
|
|
||||||
entrypoint: python generator.py # Точка входа
|
|
||||||
|
|
||||||
# Первое приложение
|
|
||||||
app1:
|
|
||||||
build:
|
|
||||||
context: ./app-1 # Путь к контексту
|
|
||||||
volumes:
|
|
||||||
- ./data:/var/data # Монтирование папок
|
|
||||||
- ./result:/var/result
|
|
||||||
depends_on:
|
|
||||||
- generator # Указываем, что запускается только после успешной работы сервиса generator
|
|
||||||
|
|
||||||
# Второе приложение, настройка аналогична сервисам выше
|
|
||||||
app2:
|
|
||||||
build:
|
|
||||||
context: ./app-2
|
|
||||||
volumes:
|
|
||||||
- ./result:/var/result
|
|
||||||
depends_on:
|
|
||||||
- app1
|
|
@ -1,50 +0,0 @@
|
|||||||
# Отчет. Лабораторная работа 4
|
|
||||||
|
|
||||||
## Описание
|
|
||||||
В ходе лабораторной работы были изучены главы туториала о работе с RabbitMQ. Результат выполнения заданий каждой главы
|
|
||||||
отражен на скриншотах в папке /images:
|
|
||||||
- Tutorial-Task1.png
|
|
||||||
![Tutorial-Task1](images/Tutorial-Task1.png)
|
|
||||||
- Tutorial-Task2.png
|
|
||||||
![Tutorial-Task2](images/Tutorial-Task2.png)
|
|
||||||
- Tutorial-Task3.png
|
|
||||||
![Tutorial-Task3](images/Tutorial-Task3.png)
|
|
||||||
|
|
||||||
Задание из 3-ей главы туториала было расширено условиями, которые были поставлены в задании к данной лабораторной работе.
|
|
||||||
Для демонстрации работы сервисов посредством ассинхронного общения через брокер сообщений RabbitMQ была выбрана
|
|
||||||
предметная область "Обработка заказов".
|
|
||||||
|
|
||||||
Сервис-издатель "Publisher" публикует в очередь сообщений событие поступления заказа с некоторым номером.
|
|
||||||
|
|
||||||
Сервисы-подписчики обрабатывают сообщения о заказах, при этом подписчики обрабатывают сообщение по-разному. Один вид
|
|
||||||
подписчика обрабатывает с задержкой в несколько секунд, другой - "мгновенно", они получают одни и те жа сообщения,
|
|
||||||
но соединены с разными очередями.
|
|
||||||
В качестве эксперимента изначально были запущены по одному экземпляру каждого вида.
|
|
||||||
На изображении Consumer2.png представлена работа мгновенно обрабатывающего подписчика. Он справляется с нагрузкой,
|
|
||||||
так как размер очереди не растет.
|
|
||||||
![Consumer 2](images/Consumer2.png)
|
|
||||||
На изображении Consumer1.png представлена работа подписчика, обрабатывающего сообщения с задержкой. Как мы видим,
|
|
||||||
в очереди накапливаются сообщения в состоянии 'Ready' - эти сообщения готовы для того, чтобы быть доставленными подписчикам.
|
|
||||||
Сервис не справляется с нагрузкой, так как отправляются сообщения быстрее, чем обрабатываются.
|
|
||||||
![Consumer 1](images/Consumer1.png)
|
|
||||||
Для того, чтобы обеспечить равную скорость отправки и обработки, увеличиваем количество экземпляров-подписчиков данного типа до трех.
|
|
||||||
На изображении видно, что теперь длина очереди не растет и система справляется с поступающими сообщениями. Также скорость "publish" и
|
|
||||||
"consumer ack" стали равны.
|
|
||||||
![Consumer 1](images/Consumer1-scaling.png)
|
|
||||||
## Как запустить
|
|
||||||
Для того, чтобы запустить сервисы, необходимо выполнить следующие действия:
|
|
||||||
1. Установить и запустить Docker Engine или Docker Desktop
|
|
||||||
2. Через консоль перейти в папку, в которой расположен файл docker-compose.yml
|
|
||||||
3. Выполнить команду для запуска брокера сообщений rabbitmq:
|
|
||||||
```
|
|
||||||
docker compose up rabbit -d
|
|
||||||
```
|
|
||||||
4. Выполнить команду для запуска остальных контейнеров:
|
|
||||||
```
|
|
||||||
docker compose up -d
|
|
||||||
```
|
|
||||||
Такой порядок запуска важен для того, чтобы брокер сообщений успел полностью запуститься
|
|
||||||
и произвести действия для того, чтобы быть готовым принимать соединения от сервисов. Потому что указания depends_on не хватает
|
|
||||||
для отслеживания завершения всех необходимых подготовительных процессов брокера.
|
|
||||||
## Видео-отчет
|
|
||||||
Работоспособность лабораторной работы можно оценить в следующем [видео](https://disk.yandex.ru/i/G0vsfp7vwazYHw).
|
|
@ -1,23 +0,0 @@
|
|||||||
# Используем образ Maven для сборки
|
|
||||||
FROM maven:3.8-eclipse-temurin-21-alpine AS build
|
|
||||||
|
|
||||||
# Устанавливаем рабочую директорию
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
# Копируем остальные исходные файлы
|
|
||||||
COPY pom.xml .
|
|
||||||
COPY src src
|
|
||||||
|
|
||||||
# Собираем весь проект
|
|
||||||
RUN mvn clean package -DskipTests
|
|
||||||
RUN mvn dependency:copy-dependencies
|
|
||||||
|
|
||||||
# Используем официальный образ JDK для запуска собранного jar-файла
|
|
||||||
FROM eclipse-temurin:21-jdk-alpine
|
|
||||||
|
|
||||||
# Копируем jar-файл из предыдущего этапа
|
|
||||||
COPY --from=build /app/target/*.jar /app.jar
|
|
||||||
COPY --from=build /app/target/dependency /
|
|
||||||
|
|
||||||
# Указываем команду для запуска приложения
|
|
||||||
CMD ["java", "-jar", "app.jar"]
|
|
@ -1,50 +0,0 @@
|
|||||||
<?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">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<groupId>ru.somecompany</groupId>
|
|
||||||
<artifactId>consumer-app</artifactId>
|
|
||||||
<version>1.0.0-SNAPSHOT</version>
|
|
||||||
|
|
||||||
<parent>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-parent</artifactId>
|
|
||||||
<version>3.2.3</version>
|
|
||||||
<relativePath/>
|
|
||||||
</parent>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<maven.compiler.source>21</maven.compiler.source>
|
|
||||||
<maven.compiler.target>21</maven.compiler.target>
|
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.rabbitmq</groupId>
|
|
||||||
<artifactId>amqp-client</artifactId>
|
|
||||||
<version>5.22.0</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.projectlombok</groupId>
|
|
||||||
<artifactId>lombok</artifactId>
|
|
||||||
<version>1.18.30</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
|
|
||||||
</project>
|
|
@ -1,15 +0,0 @@
|
|||||||
package ru.somecompany;
|
|
||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
|
|
||||||
import ru.somecompany.config.property.RabbitProperties;
|
|
||||||
|
|
||||||
@SpringBootApplication
|
|
||||||
@ConfigurationPropertiesScan(basePackageClasses = RabbitProperties.class)
|
|
||||||
public class Main {
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
SpringApplication.run(Main.class, args);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
package ru.somecompany.config;
|
|
||||||
|
|
||||||
import com.rabbitmq.client.BuiltinExchangeType;
|
|
||||||
import com.rabbitmq.client.Channel;
|
|
||||||
import com.rabbitmq.client.Connection;
|
|
||||||
import com.rabbitmq.client.ConnectionFactory;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import ru.somecompany.config.property.RabbitProperties;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.concurrent.TimeoutException;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class ConnectionFactoryConfig {
|
|
||||||
|
|
||||||
private final RabbitProperties rabbitProperties;
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public ConnectionFactory connectionFactory() {
|
|
||||||
ConnectionFactory factory = new ConnectionFactory();
|
|
||||||
factory.setHost(rabbitProperties.getHost());
|
|
||||||
factory.setPort(rabbitProperties.getPort());
|
|
||||||
return factory;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public Connection connection(ConnectionFactory connectionFactory) throws IOException, TimeoutException {
|
|
||||||
return connectionFactory.newConnection();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public Channel channel(Connection connection) throws IOException {
|
|
||||||
var exchange = rabbitProperties.getExchange();
|
|
||||||
var queue = rabbitProperties.getQueue();
|
|
||||||
var channel = connection.createChannel();
|
|
||||||
|
|
||||||
channel.exchangeDeclare(exchange, BuiltinExchangeType.FANOUT);
|
|
||||||
channel.queueDeclare(queue, true, false, true, null);
|
|
||||||
channel.queueBind(queue, exchange, "");
|
|
||||||
return channel;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
package ru.somecompany.config.property;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@ConfigurationProperties(prefix = "app.rabbit-properties")
|
|
||||||
public class RabbitProperties {
|
|
||||||
|
|
||||||
private String host;
|
|
||||||
|
|
||||||
private Integer port;
|
|
||||||
|
|
||||||
private Integer delay;
|
|
||||||
|
|
||||||
private String queue;
|
|
||||||
|
|
||||||
private String exchange;
|
|
||||||
}
|
|
@ -1,76 +0,0 @@
|
|||||||
package ru.somecompany.consumer;
|
|
||||||
|
|
||||||
import com.rabbitmq.client.AMQP;
|
|
||||||
import com.rabbitmq.client.Channel;
|
|
||||||
import com.rabbitmq.client.Connection;
|
|
||||||
import com.rabbitmq.client.DefaultConsumer;
|
|
||||||
import com.rabbitmq.client.Envelope;
|
|
||||||
import jakarta.annotation.PostConstruct;
|
|
||||||
import jakarta.annotation.PreDestroy;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import ru.somecompany.config.property.RabbitProperties;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class Consumer {
|
|
||||||
|
|
||||||
private final RabbitProperties rabbitProperties;
|
|
||||||
|
|
||||||
private final Connection connection;
|
|
||||||
private final Channel channel;
|
|
||||||
|
|
||||||
@PostConstruct
|
|
||||||
public void consume() {
|
|
||||||
try {
|
|
||||||
channel.basicQos(1);
|
|
||||||
channel.basicConsume(rabbitProperties.getQueue(), false, new DefaultConsumer(channel) {
|
|
||||||
@Override
|
|
||||||
public void handleDelivery(String consumerTag,
|
|
||||||
Envelope envelope,
|
|
||||||
AMQP.BasicProperties properties,
|
|
||||||
byte[] body) throws IOException {
|
|
||||||
long deliveryTag = envelope.getDeliveryTag();
|
|
||||||
|
|
||||||
String message = new String(body, StandardCharsets.UTF_8);
|
|
||||||
System.out.println(" [x] Received '" + message + "'");
|
|
||||||
|
|
||||||
var delay = rabbitProperties.getDelay();
|
|
||||||
try {
|
|
||||||
doWork(delay);
|
|
||||||
} finally {
|
|
||||||
System.out.println(" [x] Processed '" + message + "'");
|
|
||||||
channel.basicAck(deliveryTag, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (Exception exception) {
|
|
||||||
log.error("Error while set up connection with rabbit", exception);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void doWork(Integer delay) {
|
|
||||||
if (delay > 0) {
|
|
||||||
try {
|
|
||||||
Thread.sleep(delay);
|
|
||||||
} catch (InterruptedException _ignored) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@PreDestroy
|
|
||||||
public void cleanUp() throws Exception {
|
|
||||||
if (channel != null) {
|
|
||||||
channel.close();
|
|
||||||
}
|
|
||||||
if (connection != null) {
|
|
||||||
connection.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
server:
|
|
||||||
port: ${SERVER_PORT:8081}
|
|
||||||
|
|
||||||
app:
|
|
||||||
rabbit-properties:
|
|
||||||
host: ${RABBIT_HOST:localhost}
|
|
||||||
port: ${RABBIT_PORT:5672}
|
|
||||||
delay: ${PROCESS_DELAY:0}
|
|
||||||
queue: ${QUEUE_NAME:queue-1}
|
|
||||||
exchange: ${EXCHANGE_NAME:order-events}
|
|
@ -1,79 +0,0 @@
|
|||||||
services:
|
|
||||||
rabbit:
|
|
||||||
container_name: rabbit
|
|
||||||
image: rabbitmq:3-management
|
|
||||||
ports:
|
|
||||||
- "15672:15672"
|
|
||||||
- "5672:5672"
|
|
||||||
- "5671:5671"
|
|
||||||
networks:
|
|
||||||
- local
|
|
||||||
publisher:
|
|
||||||
build: ./publisher-app
|
|
||||||
container_name: publisher
|
|
||||||
depends_on:
|
|
||||||
- rabbit
|
|
||||||
environment:
|
|
||||||
RABBIT_HOST: rabbit
|
|
||||||
RABBIT_PORT: 5672
|
|
||||||
networks:
|
|
||||||
- local
|
|
||||||
consumer-1:
|
|
||||||
build: ./consumer-app
|
|
||||||
container_name: consumer-1
|
|
||||||
depends_on:
|
|
||||||
- rabbit
|
|
||||||
- publisher
|
|
||||||
environment:
|
|
||||||
RABBIT_HOST: rabbit
|
|
||||||
RABBIT_PORT: 5672
|
|
||||||
PROCESS_DELAY: 3000
|
|
||||||
QUEUE_NAME: queue1
|
|
||||||
EXCHANGE_NAME: order-events
|
|
||||||
networks:
|
|
||||||
- local
|
|
||||||
consumer-2:
|
|
||||||
build: ./consumer-app
|
|
||||||
container_name: consumer-2
|
|
||||||
depends_on:
|
|
||||||
- rabbit
|
|
||||||
- publisher
|
|
||||||
environment:
|
|
||||||
RABBIT_HOST: rabbit
|
|
||||||
RABBIT_PORT: 5672
|
|
||||||
PROCESS_DELAY: 0
|
|
||||||
QUEUE_NAME: queue2
|
|
||||||
EXCHANGE_NAME: order-events
|
|
||||||
networks:
|
|
||||||
- local
|
|
||||||
consumer-12:
|
|
||||||
build: ./consumer-app
|
|
||||||
container_name: consumer-12
|
|
||||||
depends_on:
|
|
||||||
- rabbit
|
|
||||||
- publisher
|
|
||||||
environment:
|
|
||||||
RABBIT_HOST: rabbit
|
|
||||||
RABBIT_PORT: 5672
|
|
||||||
PROCESS_DELAY: 3000
|
|
||||||
QUEUE_NAME: queue1
|
|
||||||
EXCHANGE_NAME: order-events
|
|
||||||
networks:
|
|
||||||
- local
|
|
||||||
consumer-13:
|
|
||||||
build: ./consumer-app
|
|
||||||
container_name: consumer-13
|
|
||||||
depends_on:
|
|
||||||
- rabbit
|
|
||||||
- publisher
|
|
||||||
environment:
|
|
||||||
RABBIT_HOST: rabbit
|
|
||||||
RABBIT_PORT: 5672
|
|
||||||
PROCESS_DELAY: 3000
|
|
||||||
QUEUE_NAME: queue1
|
|
||||||
EXCHANGE_NAME: order-events
|
|
||||||
networks:
|
|
||||||
- local
|
|
||||||
|
|
||||||
networks:
|
|
||||||
local:
|
|
@ -1,34 +0,0 @@
|
|||||||
<?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">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<groupId>ru.somecompany</groupId>
|
|
||||||
<artifactId>helloworld-tutorial</artifactId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<maven.compiler.source>21</maven.compiler.source>
|
|
||||||
<maven.compiler.target>21</maven.compiler.target>
|
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.rabbitmq</groupId>
|
|
||||||
<artifactId>amqp-client</artifactId>
|
|
||||||
<version>5.22.0</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.slf4j</groupId>
|
|
||||||
<artifactId>slf4j-api</artifactId>
|
|
||||||
<version>1.7.5</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.slf4j</groupId>
|
|
||||||
<artifactId>slf4j-log4j12</artifactId>
|
|
||||||
<version>1.7.5</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</project>
|
|
@ -1,28 +0,0 @@
|
|||||||
package ru.somecompany;
|
|
||||||
|
|
||||||
import com.rabbitmq.client.Channel;
|
|
||||||
import com.rabbitmq.client.Connection;
|
|
||||||
import com.rabbitmq.client.ConnectionFactory;
|
|
||||||
import com.rabbitmq.client.DeliverCallback;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.concurrent.TimeoutException;
|
|
||||||
|
|
||||||
public class Main {
|
|
||||||
|
|
||||||
private static final String QUEUE_NAME = "hello-world";
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
ConnectionFactory factory = new ConnectionFactory();
|
|
||||||
factory.setHost("localhost");
|
|
||||||
try(Connection connection = factory.newConnection();
|
|
||||||
Channel channel = connection.createChannel();) {
|
|
||||||
var sender = new Sender(channel);
|
|
||||||
var receiver = new Receiver(channel);
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
System.out.println(" [*] Error in Hello-World");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
package ru.somecompany;
|
|
||||||
|
|
||||||
import com.rabbitmq.client.Channel;
|
|
||||||
import com.rabbitmq.client.DeliverCallback;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class Receiver {
|
|
||||||
|
|
||||||
private static final String QUEUE_NAME = "hello-world";
|
|
||||||
|
|
||||||
public Receiver(Channel channel) throws IOException {
|
|
||||||
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
|
|
||||||
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
|
|
||||||
String message = new String(delivery.getBody(), "UTF-8");
|
|
||||||
System.out.println(" [x] Received '" + message + "'");
|
|
||||||
};
|
|
||||||
channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> { });
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
package ru.somecompany;
|
|
||||||
|
|
||||||
import com.rabbitmq.client.Channel;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
|
|
||||||
public class Sender {
|
|
||||||
|
|
||||||
private static final String QUEUE_NAME = "hello-world";
|
|
||||||
|
|
||||||
public Sender(Channel channel) throws IOException {
|
|
||||||
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
|
|
||||||
String message = "Hello World!";
|
|
||||||
channel.basicPublish("", QUEUE_NAME, null, message.getBytes(StandardCharsets.UTF_8));
|
|
||||||
System.out.println(" [x] Sent '" + message + "'");
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
# Root logger option
|
|
||||||
log4j.rootLogger=INFO, stdout
|
|
||||||
|
|
||||||
# Direct log messages to stdout
|
|
||||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
|
||||||
log4j.appender.stdout.Target=System.out
|
|
||||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
|
||||||
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
|
|
Before Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 39 KiB |
Before Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 101 KiB |
Before Width: | Height: | Size: 128 KiB |
Before Width: | Height: | Size: 848 KiB |
@ -1,38 +0,0 @@
|
|||||||
target/
|
|
||||||
!.mvn/wrapper/maven-wrapper.jar
|
|
||||||
!**/src/main/**/target/
|
|
||||||
!**/src/test/**/target/
|
|
||||||
|
|
||||||
### IntelliJ IDEA ###
|
|
||||||
.idea/modules.xml
|
|
||||||
.idea/jarRepositories.xml
|
|
||||||
.idea/compiler.xml
|
|
||||||
.idea/libraries/
|
|
||||||
*.iws
|
|
||||||
*.iml
|
|
||||||
*.ipr
|
|
||||||
|
|
||||||
### Eclipse ###
|
|
||||||
.apt_generated
|
|
||||||
.classpath
|
|
||||||
.factorypath
|
|
||||||
.project
|
|
||||||
.settings
|
|
||||||
.springBeans
|
|
||||||
.sts4-cache
|
|
||||||
|
|
||||||
### NetBeans ###
|
|
||||||
/nbproject/private/
|
|
||||||
/nbbuild/
|
|
||||||
/dist/
|
|
||||||
/nbdist/
|
|
||||||
/.nb-gradle/
|
|
||||||
build/
|
|
||||||
!**/src/main/**/build/
|
|
||||||
!**/src/test/**/build/
|
|
||||||
|
|
||||||
### VS Code ###
|
|
||||||
.vscode/
|
|
||||||
|
|
||||||
### Mac OS ###
|
|
||||||
.DS_Store
|
|
@ -1,21 +0,0 @@
|
|||||||
# Используем образ Maven для сборки
|
|
||||||
FROM maven:3.8-eclipse-temurin-21-alpine AS build
|
|
||||||
|
|
||||||
# Устанавливаем рабочую директорию
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
# Копируем остальные исходные файлы
|
|
||||||
COPY pom.xml .
|
|
||||||
COPY src src
|
|
||||||
|
|
||||||
# Собираем весь проект
|
|
||||||
RUN mvn clean package -DskipTests
|
|
||||||
|
|
||||||
# Используем официальный образ JDK для запуска собранного jar-файла
|
|
||||||
FROM eclipse-temurin:21-jdk-alpine
|
|
||||||
|
|
||||||
# Копируем jar-файл из предыдущего этапа
|
|
||||||
COPY --from=build /app/target/*.jar /app.jar
|
|
||||||
|
|
||||||
# Указываем команду для запуска приложения
|
|
||||||
CMD ["java", "-jar", "app.jar"]
|
|
@ -1,49 +0,0 @@
|
|||||||
<?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">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<groupId>ru.somecompany</groupId>
|
|
||||||
<artifactId>publisher-app</artifactId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
|
|
||||||
<parent>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-parent</artifactId>
|
|
||||||
<version>3.2.3</version>
|
|
||||||
<relativePath/>
|
|
||||||
</parent>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<maven.compiler.source>21</maven.compiler.source>
|
|
||||||
<maven.compiler.target>21</maven.compiler.target>
|
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.projectlombok</groupId>
|
|
||||||
<artifactId>lombok</artifactId>
|
|
||||||
<version>1.18.30</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.rabbitmq</groupId>
|
|
||||||
<artifactId>amqp-client</artifactId>
|
|
||||||
<version>5.22.0</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
</project>
|
|
@ -1,17 +0,0 @@
|
|||||||
package ru.somecompany;
|
|
||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
|
|
||||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
|
||||||
import ru.somecompany.config.property.RabbitProperties;
|
|
||||||
|
|
||||||
@EnableScheduling
|
|
||||||
@SpringBootApplication
|
|
||||||
@ConfigurationPropertiesScan(basePackageClasses = RabbitProperties.class)
|
|
||||||
public class Main {
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
SpringApplication.run(Main.class, args);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
package ru.somecompany.config;
|
|
||||||
|
|
||||||
import com.rabbitmq.client.BuiltinExchangeType;
|
|
||||||
import com.rabbitmq.client.Channel;
|
|
||||||
import com.rabbitmq.client.Connection;
|
|
||||||
import com.rabbitmq.client.ConnectionFactory;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import ru.somecompany.config.property.RabbitProperties;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.concurrent.TimeoutException;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class ConnectionFactoryConfig {
|
|
||||||
|
|
||||||
private final RabbitProperties rabbitProperties;
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public ConnectionFactory connectionFactory() {
|
|
||||||
ConnectionFactory factory = new ConnectionFactory();
|
|
||||||
factory.setHost(rabbitProperties.getHost());
|
|
||||||
factory.setPort(rabbitProperties.getPort());
|
|
||||||
return factory;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public Connection connection(ConnectionFactory connectionFactory) throws IOException, TimeoutException {
|
|
||||||
return connectionFactory.newConnection();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public Channel channel(Connection connection) throws IOException {
|
|
||||||
var channel = connection.createChannel();
|
|
||||||
channel.exchangeDeclare(rabbitProperties.getExchange(), BuiltinExchangeType.FANOUT);
|
|
||||||
return channel;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
package ru.somecompany.config.property;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@ConfigurationProperties(prefix = "app.rabbit-properties")
|
|
||||||
public class RabbitProperties {
|
|
||||||
|
|
||||||
private String host;
|
|
||||||
|
|
||||||
private Integer port;
|
|
||||||
|
|
||||||
private String exchange;
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
package ru.somecompany.scheduler;
|
|
||||||
|
|
||||||
import com.rabbitmq.client.BuiltinExchangeType;
|
|
||||||
import com.rabbitmq.client.Channel;
|
|
||||||
import com.rabbitmq.client.Connection;
|
|
||||||
import com.rabbitmq.client.ConnectionFactory;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.concurrent.TimeoutException;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class SenderScheduler {
|
|
||||||
|
|
||||||
private static final String EXCHANGE_NAME = "order-events";
|
|
||||||
private static final String MESSAGE = "Поступил заказ №%d";
|
|
||||||
private Integer index = 0;
|
|
||||||
|
|
||||||
private final ConnectionFactory connectionFactory;
|
|
||||||
private final Connection connection;
|
|
||||||
private final Channel channel;
|
|
||||||
|
|
||||||
@Scheduled(cron = "*/1 * * * * *")
|
|
||||||
public void sendMessage() {
|
|
||||||
try {
|
|
||||||
var message = String.format(MESSAGE, index);
|
|
||||||
|
|
||||||
channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes(StandardCharsets.UTF_8));
|
|
||||||
index++;
|
|
||||||
System.out.println(" [x] Sent '" + message + "'");
|
|
||||||
} catch (IOException e) {
|
|
||||||
System.out.println(" [x] Error while send message");
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
server:
|
|
||||||
port: ${SERVER_PORT:8080}
|
|
||||||
|
|
||||||
app:
|
|
||||||
rabbit-properties:
|
|
||||||
host: ${RABBIT_HOST:localhost}
|
|
||||||
port: ${RABBIT_PORT:5672}
|
|
||||||
exchange: ${EXCHANGE_NAME:order-events}
|
|
@ -1,30 +0,0 @@
|
|||||||
<?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">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<groupId>ru.somecompany</groupId>
|
|
||||||
<artifactId>workqueue-tutorial</artifactId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<maven.compiler.source>21</maven.compiler.source>
|
|
||||||
<maven.compiler.target>21</maven.compiler.target>
|
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.rabbitmq</groupId>
|
|
||||||
<artifactId>amqp-client</artifactId>
|
|
||||||
<version>5.22.0</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.slf4j</groupId>
|
|
||||||
<artifactId>slf4j-log4j12</artifactId>
|
|
||||||
<version>1.7.5</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
</project>
|
|
@ -1,23 +0,0 @@
|
|||||||
package ru.somecompany;
|
|
||||||
|
|
||||||
import com.rabbitmq.client.Channel;
|
|
||||||
import com.rabbitmq.client.Connection;
|
|
||||||
import com.rabbitmq.client.ConnectionFactory;
|
|
||||||
|
|
||||||
public class Main {
|
|
||||||
|
|
||||||
public static final String QUEUE_NAME = "task_queue";
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
ConnectionFactory factory = new ConnectionFactory();
|
|
||||||
factory.setHost("localhost");
|
|
||||||
try(Connection connection = factory.newConnection();
|
|
||||||
Channel channel = connection.createChannel();) {
|
|
||||||
var sender = new Sender(channel);
|
|
||||||
sender.send("Work Queue message");
|
|
||||||
var receiver = new Receiver(channel);
|
|
||||||
} catch (Exception e) {
|
|
||||||
System.out.println(" [*] Error in Work-Queue: " + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,44 +0,0 @@
|
|||||||
package ru.somecompany;
|
|
||||||
|
|
||||||
import com.rabbitmq.client.Channel;
|
|
||||||
import com.rabbitmq.client.DeliverCallback;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
|
|
||||||
import static ru.somecompany.Main.QUEUE_NAME;
|
|
||||||
|
|
||||||
public class Receiver {
|
|
||||||
|
|
||||||
public Receiver(Channel channel) throws IOException {
|
|
||||||
channel.queueDeclare(QUEUE_NAME, true, false, false, null);
|
|
||||||
System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
|
|
||||||
|
|
||||||
channel.basicQos(1);
|
|
||||||
|
|
||||||
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
|
|
||||||
String message = new String(delivery.getBody(), StandardCharsets.UTF_8);
|
|
||||||
|
|
||||||
System.out.println(" [x] Received '" + message + "'");
|
|
||||||
try {
|
|
||||||
doWork(message);
|
|
||||||
} finally {
|
|
||||||
System.out.println(" [x] Done");
|
|
||||||
channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
channel.basicConsume(QUEUE_NAME, false, deliverCallback, consumerTag -> { });
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void doWork(String task) {
|
|
||||||
for (char ch : task.toCharArray()) {
|
|
||||||
if (ch == '.') {
|
|
||||||
try {
|
|
||||||
Thread.sleep(1000);
|
|
||||||
} catch (InterruptedException _ignored) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
package ru.somecompany;
|
|
||||||
|
|
||||||
import com.rabbitmq.client.Channel;
|
|
||||||
import com.rabbitmq.client.MessageProperties;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
|
|
||||||
import static ru.somecompany.Main.QUEUE_NAME;
|
|
||||||
|
|
||||||
public class Sender {
|
|
||||||
|
|
||||||
private Channel channel;
|
|
||||||
|
|
||||||
public Sender(Channel channel) throws IOException {
|
|
||||||
channel.queueDeclare(QUEUE_NAME, true, false, false, null);
|
|
||||||
this.channel = channel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void send(String msg) throws IOException {
|
|
||||||
String message = String.join(" ", msg);
|
|
||||||
|
|
||||||
channel.basicPublish("", QUEUE_NAME,
|
|
||||||
MessageProperties.PERSISTENT_TEXT_PLAIN,
|
|
||||||
message.getBytes("UTF-8"));
|
|
||||||
System.out.println(" [x] Sent '" + message + "'");
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
# Root logger option
|
|
||||||
log4j.rootLogger=INFO, stdout
|
|
||||||
|
|
||||||
# Direct log messages to stdout
|
|
||||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
|
||||||
log4j.appender.stdout.Target=System.out
|
|
||||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
|
||||||
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
|
|
@ -1,30 +0,0 @@
|
|||||||
# Отчет. Лабораторная работа 5
|
|
||||||
|
|
||||||
## Описание
|
|
||||||
В рамках лабораторной работы была реализована программа, которая производит умножение матриц с применением последовательного и паралелльного алгоритма.
|
|
||||||
При этом последовательный алгоритм достигается с помощью выделения одного потока на выполнение.
|
|
||||||
|
|
||||||
При указании одного потока подзадачи по умножению матриц полностью выполняются одним потоком. В качестве подзадачи было
|
|
||||||
выбрано нахождение строки результирующей матрицы.
|
|
||||||
|
|
||||||
По условию задания необходимо было замерить результаты выполнения алгоритмов на квадратных матрицах размерами 100x100,
|
|
||||||
300x300, 500x500. На всех прогонах можно увидеть, что последовательное выполнение умножения матриц происходит медленнее
|
|
||||||
в несколько раз медленее. При этом чем больше потоков выделяется для выполнения подзадач, тем быстрее выполняется
|
|
||||||
алгоритм параллельного умножения.
|
|
||||||
|
|
||||||
Результаты представлены на следующих изображениях:
|
|
||||||
![100](images/100x100.PNG)
|
|
||||||
![300](images/300x300.PNG)
|
|
||||||
![500](images/500x500.PNG)
|
|
||||||
|
|
||||||
## Как запустить
|
|
||||||
Необходимо иметь установленную JDK 21. Можно воспользоваться встроенным в нее компилятором (javac), а затем запустить исполняемый файл (java)
|
|
||||||
или запускать из среды разработки.
|
|
||||||
При запуске нужно указать аргументы командной строки:
|
|
||||||
1. размер матриц (integer)
|
|
||||||
2. режим отладки (boolean) - позволяет выводить в консоль исходные матрицы и промежуточные результаты работы
|
|
||||||
|
|
||||||
## Видео-отчет
|
|
||||||
Работоспособность лабораторной работы можно оценить в следующем [видео](https://disk.yandex.ru/i/ZafQV9CGjBIKIw).
|
|
||||||
Запуск происходил через IDEA с различными конфигурациями запуска (отличался размер умножаемых матриц и параметр отладки),
|
|
||||||
чтобы увидеть результаты выполнения на матрицах всех размеров, необходимых по условию задачи.
|
|
Before Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 30 KiB |
38
borschevskaya_anna_lab_5/matrix-mul/.gitignore
vendored
@ -1,38 +0,0 @@
|
|||||||
target/
|
|
||||||
!.mvn/wrapper/maven-wrapper.jar
|
|
||||||
!**/src/main/**/target/
|
|
||||||
!**/src/test/**/target/
|
|
||||||
|
|
||||||
### IntelliJ IDEA ###
|
|
||||||
.idea/modules.xml
|
|
||||||
.idea/jarRepositories.xml
|
|
||||||
.idea/compiler.xml
|
|
||||||
.idea/libraries/
|
|
||||||
*.iws
|
|
||||||
*.iml
|
|
||||||
*.ipr
|
|
||||||
|
|
||||||
### Eclipse ###
|
|
||||||
.apt_generated
|
|
||||||
.classpath
|
|
||||||
.factorypath
|
|
||||||
.project
|
|
||||||
.settings
|
|
||||||
.springBeans
|
|
||||||
.sts4-cache
|
|
||||||
|
|
||||||
### NetBeans ###
|
|
||||||
/nbproject/private/
|
|
||||||
/nbbuild/
|
|
||||||
/dist/
|
|
||||||
/nbdist/
|
|
||||||
/.nb-gradle/
|
|
||||||
build/
|
|
||||||
!**/src/main/**/build/
|
|
||||||
!**/src/test/**/build/
|
|
||||||
|
|
||||||
### VS Code ###
|
|
||||||
.vscode/
|
|
||||||
|
|
||||||
### Mac OS ###
|
|
||||||
.DS_Store
|
|
@ -1,17 +0,0 @@
|
|||||||
<?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">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<groupId>ru.uni.rvip</groupId>
|
|
||||||
<artifactId>matrix-mul</artifactId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<maven.compiler.source>21</maven.compiler.source>
|
|
||||||
<maven.compiler.target>21</maven.compiler.target>
|
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
</project>
|
|
@ -1,98 +0,0 @@
|
|||||||
package ru.uni.rvip;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Random;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.Future;
|
|
||||||
|
|
||||||
public class Main {
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
var size = Integer.parseInt(args[0]);
|
|
||||||
var debugMode = Boolean.parseBoolean(args[1]);
|
|
||||||
System.out.printf("Размер матриц %dx%d\n", size, size);
|
|
||||||
|
|
||||||
var matrix1 = createRandomMatrix(size);
|
|
||||||
if (debugMode) {
|
|
||||||
printMatrix(matrix1);
|
|
||||||
}
|
|
||||||
var matrix2 = createRandomMatrix(size);
|
|
||||||
if (debugMode) {
|
|
||||||
printMatrix(matrix2);
|
|
||||||
}
|
|
||||||
var startTime = System.currentTimeMillis();
|
|
||||||
var result1 = mulMatrix(matrix1, matrix2, 1); // сначала передаем в метод 1 поток-исполнитель
|
|
||||||
var timeOfExecution = System.currentTimeMillis() - startTime;
|
|
||||||
if (debugMode) {
|
|
||||||
printMatrix(result1);
|
|
||||||
}
|
|
||||||
System.out.printf("Время умножения матриц с помощью последовательного алгоритма: %d ms\n", timeOfExecution);
|
|
||||||
|
|
||||||
var threadCounts = new int[] {2, 4, 6, 8};
|
|
||||||
for (var threadCount: threadCounts) { // тестирование на разном количестве потоков-исполнителей
|
|
||||||
startTime = System.currentTimeMillis();
|
|
||||||
var result2 = mulMatrix(matrix1, matrix2, threadCount);
|
|
||||||
timeOfExecution = System.currentTimeMillis() - startTime;
|
|
||||||
if (debugMode) {
|
|
||||||
printMatrix(result2);
|
|
||||||
}
|
|
||||||
System.out.printf("Время умножения матриц с помощью параллельного алгоритма (%d threads): %d ms\n",threadCount, timeOfExecution);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int[][] createRandomMatrix(Integer size) {
|
|
||||||
var matrix = new int[size][size];
|
|
||||||
var random = new Random();
|
|
||||||
for (var i = 0; i < size; i++) {
|
|
||||||
for (var j = 0; j < size; j++) {
|
|
||||||
matrix[i][j] = random.nextInt(100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return matrix;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int[][] mulMatrix(int[][] matrix1, int[][] matrix2, Integer threadCount) {
|
|
||||||
if (matrix1[0].length != matrix2.length) {
|
|
||||||
throw new IllegalArgumentException("Количество столбцов первой матрицы должна соответствовать количеству строк второй матрицы");
|
|
||||||
}
|
|
||||||
var rows = matrix2.length;
|
|
||||||
var columns = matrix1[0].length;
|
|
||||||
var result = new int[columns][rows];
|
|
||||||
try (var executorService = Executors.newFixedThreadPool(threadCount)) {
|
|
||||||
var futures = new ArrayList<Future<Integer>>();
|
|
||||||
for (int i = 0; i < rows; i++) {
|
|
||||||
final int rowI = i;
|
|
||||||
futures.add(executorService.submit(() -> calculate(rowI, matrix1, matrix2, result)));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var future : futures) {
|
|
||||||
future.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
executorService.shutdown();
|
|
||||||
return result;
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
throw new RuntimeException("Ошибка во время выполнения алгоритма");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int calculate(int i, int[][] matrix1, int[][] matrix2, int[][] result) {
|
|
||||||
for (int j = 0; j < matrix1[0].length; j++) {
|
|
||||||
result[i][j] = 0;
|
|
||||||
for (int k = 0; k < matrix2[0].length; k++) {
|
|
||||||
result[i][j] += matrix1[i][k] * matrix2[k][j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void printMatrix(int[][] matrix) {
|
|
||||||
for (int[] ints : matrix) {
|
|
||||||
for (int elem : ints) {
|
|
||||||
System.out.printf("%5d\t", elem);
|
|
||||||
}
|
|
||||||
System.out.println();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
**/.classpath
|
|
||||||
**/.dockerignore
|
|
||||||
**/.env
|
|
||||||
**/.git
|
|
||||||
**/.gitignore
|
|
||||||
**/.project
|
|
||||||
**/.settings
|
|
||||||
**/.toolstarget
|
|
||||||
**/.vs
|
|
||||||
**/.vscode
|
|
||||||
**/*.*proj.user
|
|
||||||
**/*.dbmdl
|
|
||||||
**/*.jfm
|
|
||||||
**/azds.yaml
|
|
||||||
**/bin
|
|
||||||
**/charts
|
|
||||||
**/docker-compose*
|
|
||||||
**/Dockerfile*
|
|
||||||
**/node_modules
|
|
||||||
**/npm-debug.log
|
|
||||||
**/obj
|
|
||||||
**/secrets.dev.yaml
|
|
||||||
**/values.dev.yaml
|
|
||||||
LICENSE
|
|
||||||
README.md
|
|
||||||
!**/.gitignore
|
|
||||||
!.git/HEAD
|
|
||||||
!.git/config
|
|
||||||
!.git/packed-refs
|
|
||||||
!.git/refs/heads/**
|
|
@ -1,17 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<OutputType>Exe</OutputType>
|
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
|
||||||
<DockerfileContext>.</DockerfileContext>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.20.1" />
|
|
||||||
<PackageReference Include="RabbitMQ.Client" Version="6.8.1" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<PropertyGroup>
|
|
||||||
<ActiveDebugProfile>Container (Dockerfile)</ActiveDebugProfile>
|
|
||||||
</PropertyGroup>
|
|
||||||
</Project>
|
|
@ -1,25 +0,0 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
|
||||||
# Visual Studio Version 17
|
|
||||||
VisualStudioVersion = 17.10.35004.147
|
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsumerDelay", "ConsumerDelay.csproj", "{4DD86D5F-D90D-4BBB-AAA4-F16DA855B51E}"
|
|
||||||
EndProject
|
|
||||||
Global
|
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
|
||||||
Debug|Any CPU = Debug|Any CPU
|
|
||||||
Release|Any CPU = Release|Any CPU
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
|
||||||
{4DD86D5F-D90D-4BBB-AAA4-F16DA855B51E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{4DD86D5F-D90D-4BBB-AAA4-F16DA855B51E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{4DD86D5F-D90D-4BBB-AAA4-F16DA855B51E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{4DD86D5F-D90D-4BBB-AAA4-F16DA855B51E}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
|
||||||
HideSolutionNode = FALSE
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
|
||||||
SolutionGuid = {3E7AED20-0868-42FE-9C39-581BC9D2BB22}
|
|
||||||
EndGlobalSection
|
|
||||||
EndGlobal
|
|
@ -1,22 +0,0 @@
|
|||||||
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
|
|
||||||
|
|
||||||
FROM mcr.microsoft.com/dotnet/runtime:6.0 AS base
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
|
|
||||||
ARG BUILD_CONFIGURATION=Release
|
|
||||||
WORKDIR /src
|
|
||||||
COPY ["ConsumerDelay.csproj", "."]
|
|
||||||
RUN dotnet restore "./ConsumerDelay.csproj"
|
|
||||||
COPY . .
|
|
||||||
WORKDIR "/src/."
|
|
||||||
RUN dotnet build "./ConsumerDelay.csproj" -c $BUILD_CONFIGURATION -o /app/build
|
|
||||||
|
|
||||||
FROM build AS publish
|
|
||||||
ARG BUILD_CONFIGURATION=Release
|
|
||||||
RUN dotnet publish "./ConsumerDelay.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
|
|
||||||
|
|
||||||
FROM base AS final
|
|
||||||
WORKDIR /app
|
|
||||||
COPY --from=publish /app/publish .
|
|
||||||
ENTRYPOINT ["dotnet", "ConsumerDelay.dll"]
|
|
@ -1,24 +0,0 @@
|
|||||||
using ConsumerDelay;
|
|
||||||
|
|
||||||
var rabbitHost = Environment.GetEnvironmentVariable("RABBIT_HOST") ?? "localhost";
|
|
||||||
var rabbitUsername = Environment.GetEnvironmentVariable("RABBIT_USERNAME") ?? "user";
|
|
||||||
var rabbitPassword = Environment.GetEnvironmentVariable("RABBIT_PASSWORD") ?? "password";
|
|
||||||
var rabbitExchange = Environment.GetEnvironmentVariable("RABBIT_EXCHANGE") ?? "ReportIn";
|
|
||||||
var rabbitQueue = Environment.GetEnvironmentVariable("RABBIT_QUEUE") ?? "Second";
|
|
||||||
|
|
||||||
Thread.Sleep(2000);
|
|
||||||
|
|
||||||
var receiver = new Receiver(rabbitHost, rabbitUsername, rabbitPassword);
|
|
||||||
|
|
||||||
receiver.SubscribeTo(rabbitExchange, (message) =>
|
|
||||||
{
|
|
||||||
var rnd = new Random();
|
|
||||||
|
|
||||||
Console.WriteLine($"Пришло сообщение: {message}");
|
|
||||||
|
|
||||||
Thread.Sleep(rnd.Next(2000, 3000));
|
|
||||||
Console.WriteLine($"Обработка сообщения завершена");
|
|
||||||
},
|
|
||||||
rabbitQueue);
|
|
||||||
|
|
||||||
while (true) ;
|
|
@ -1,82 +0,0 @@
|
|||||||
using RabbitMQ.Client;
|
|
||||||
using RabbitMQ.Client.Events;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace ConsumerDelay
|
|
||||||
{
|
|
||||||
public class Receiver : IDisposable
|
|
||||||
{
|
|
||||||
private readonly ConnectionFactory _connectionFactory;
|
|
||||||
private readonly IConnection _connection;
|
|
||||||
private readonly IModel _channel;
|
|
||||||
|
|
||||||
public Dictionary<string, HashSet<string>> Queues { get; private set; } = new();
|
|
||||||
|
|
||||||
public Receiver(string brockerHost, string brockerUsername, string brockerPassword)
|
|
||||||
{
|
|
||||||
_connectionFactory = new ConnectionFactory() { HostName = brockerHost, UserName = brockerUsername, Password = brockerPassword };
|
|
||||||
_connection = _connectionFactory.CreateConnection();
|
|
||||||
_channel = _connection.CreateModel();
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool SubscribeTo(string exchange, Action<string> handler, string? queueName = null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!Queues.ContainsKey(exchange))
|
|
||||||
{
|
|
||||||
_channel.ExchangeDeclare(exchange: "logs", type: ExchangeType.Fanout);
|
|
||||||
Queues.Add(exchange, new HashSet<string>());
|
|
||||||
}
|
|
||||||
if (queueName != null)
|
|
||||||
_channel.QueueDeclare(queue: queueName,
|
|
||||||
durable: true,
|
|
||||||
exclusive: false,
|
|
||||||
autoDelete: false,
|
|
||||||
arguments: null);
|
|
||||||
|
|
||||||
queueName = queueName ?? _channel.QueueDeclare().QueueName;
|
|
||||||
|
|
||||||
|
|
||||||
_channel.QueueBind(queue: queueName,
|
|
||||||
exchange: exchange,
|
|
||||||
routingKey: string.Empty);
|
|
||||||
|
|
||||||
var consumer = new EventingBasicConsumer(_channel);
|
|
||||||
consumer.Received += (model, ea) =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var message = Encoding.UTF8.GetString(ea.Body.ToArray());
|
|
||||||
handler(message);
|
|
||||||
_channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine(ex.Message);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
_channel.BasicConsume(queue: queueName,
|
|
||||||
autoAck: false,
|
|
||||||
consumer: consumer);
|
|
||||||
|
|
||||||
Queues[exchange].Add(queueName);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine(ex.Message);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
~Receiver() => Dispose();
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_connection.Dispose();
|
|
||||||
_channel.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
**/.classpath
|
|
||||||
**/.dockerignore
|
|
||||||
**/.env
|
|
||||||
**/.git
|
|
||||||
**/.gitignore
|
|
||||||
**/.project
|
|
||||||
**/.settings
|
|
||||||
**/.toolstarget
|
|
||||||
**/.vs
|
|
||||||
**/.vscode
|
|
||||||
**/*.*proj.user
|
|
||||||
**/*.dbmdl
|
|
||||||
**/*.jfm
|
|
||||||
**/azds.yaml
|
|
||||||
**/bin
|
|
||||||
**/charts
|
|
||||||
**/docker-compose*
|
|
||||||
**/Dockerfile*
|
|
||||||
**/node_modules
|
|
||||||
**/npm-debug.log
|
|
||||||
**/obj
|
|
||||||
**/secrets.dev.yaml
|
|
||||||
**/values.dev.yaml
|
|
||||||
LICENSE
|
|
||||||
README.md
|
|
||||||
!**/.gitignore
|
|
||||||
!.git/HEAD
|
|
||||||
!.git/config
|
|
||||||
!.git/packed-refs
|
|
||||||
!.git/refs/heads/**
|
|
@ -1,17 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<OutputType>Exe</OutputType>
|
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
|
||||||
<DockerfileContext>.</DockerfileContext>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.20.1" />
|
|
||||||
<PackageReference Include="RabbitMQ.Client" Version="6.8.1" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<PropertyGroup>
|
|
||||||
<ActiveDebugProfile>Container (Dockerfile)</ActiveDebugProfile>
|
|
||||||
</PropertyGroup>
|
|
||||||
</Project>
|
|
@ -1,25 +0,0 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
|
||||||
# Visual Studio Version 17
|
|
||||||
VisualStudioVersion = 17.10.35004.147
|
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsumerSimple", "ConsumerSimple.csproj", "{ACA8DE52-E29E-41BA-B3DA-213AF316685E}"
|
|
||||||
EndProject
|
|
||||||
Global
|
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
|
||||||
Debug|Any CPU = Debug|Any CPU
|
|
||||||
Release|Any CPU = Release|Any CPU
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
|
||||||
{ACA8DE52-E29E-41BA-B3DA-213AF316685E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{ACA8DE52-E29E-41BA-B3DA-213AF316685E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{ACA8DE52-E29E-41BA-B3DA-213AF316685E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{ACA8DE52-E29E-41BA-B3DA-213AF316685E}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
|
||||||
HideSolutionNode = FALSE
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
|
||||||
SolutionGuid = {73265D6C-436C-470E-AE8A-17047E6C2ECC}
|
|
||||||
EndGlobalSection
|
|
||||||
EndGlobal
|
|
@ -1,22 +0,0 @@
|
|||||||
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
|
|
||||||
|
|
||||||
FROM mcr.microsoft.com/dotnet/runtime:6.0 AS base
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
|
|
||||||
ARG BUILD_CONFIGURATION=Release
|
|
||||||
WORKDIR /src
|
|
||||||
COPY ["ConsumerSimple.csproj", "."]
|
|
||||||
RUN dotnet restore "./ConsumerSimple.csproj"
|
|
||||||
COPY . .
|
|
||||||
WORKDIR "/src/."
|
|
||||||
RUN dotnet build "./ConsumerSimple.csproj" -c $BUILD_CONFIGURATION -o /app/build
|
|
||||||
|
|
||||||
FROM build AS publish
|
|
||||||
ARG BUILD_CONFIGURATION=Release
|
|
||||||
RUN dotnet publish "./ConsumerSimple.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
|
|
||||||
|
|
||||||
FROM base AS final
|
|
||||||
WORKDIR /app
|
|
||||||
COPY --from=publish /app/publish .
|
|
||||||
ENTRYPOINT ["dotnet", "ConsumerSimple.dll"]
|
|
@ -1,23 +0,0 @@
|
|||||||
using ConsumerSimple;
|
|
||||||
|
|
||||||
var rabbitHost = Environment.GetEnvironmentVariable("RABBIT_HOST") ?? "localhost";
|
|
||||||
var rabbitUsername = Environment.GetEnvironmentVariable("RABBIT_USERNAME") ?? "user";
|
|
||||||
var rabbitPassword = Environment.GetEnvironmentVariable("RABBIT_PASSWORD") ?? "password";
|
|
||||||
var rabbitExchange = Environment.GetEnvironmentVariable("RABBIT_EXCHANGE") ?? "ReportIn";
|
|
||||||
var rabbitQueue = Environment.GetEnvironmentVariable("RABBIT_QUEUE") ?? "First";
|
|
||||||
|
|
||||||
Thread.Sleep(2000);
|
|
||||||
|
|
||||||
var receiver = new Receiver(rabbitHost, rabbitUsername, rabbitPassword);
|
|
||||||
|
|
||||||
receiver.SubscribeTo(rabbitExchange, (message) =>
|
|
||||||
{
|
|
||||||
var rnd = new Random();
|
|
||||||
|
|
||||||
Console.WriteLine($"Пришло сообщение: {message}");
|
|
||||||
|
|
||||||
Console.WriteLine($"Сообщение обрабатывается мгновенно");
|
|
||||||
},
|
|
||||||
rabbitQueue);
|
|
||||||
|
|
||||||
while (true) ;
|
|
@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
"profiles": {
|
|
||||||
"ConsumerSimple": {
|
|
||||||
"commandName": "Project"
|
|
||||||
},
|
|
||||||
"Container (Dockerfile)": {
|
|
||||||
"commandName": "Docker"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,82 +0,0 @@
|
|||||||
using RabbitMQ.Client;
|
|
||||||
using RabbitMQ.Client.Events;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace ConsumerSimple
|
|
||||||
{
|
|
||||||
public class Receiver : IDisposable
|
|
||||||
{
|
|
||||||
private readonly ConnectionFactory _connectionFactory;
|
|
||||||
private readonly IConnection _connection;
|
|
||||||
private readonly IModel _channel;
|
|
||||||
|
|
||||||
public Dictionary<string, HashSet<string>> Queues { get; private set; } = new();
|
|
||||||
|
|
||||||
public Receiver(string brockerHost, string brockerUsername, string brockerPassword)
|
|
||||||
{
|
|
||||||
_connectionFactory = new ConnectionFactory() { HostName = brockerHost, UserName = brockerUsername, Password = brockerPassword };
|
|
||||||
_connection = _connectionFactory.CreateConnection();
|
|
||||||
_channel = _connection.CreateModel();
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool SubscribeTo(string exchange, Action<string> handler, string? queueName = null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!Queues.ContainsKey(exchange))
|
|
||||||
{
|
|
||||||
_channel.ExchangeDeclare(exchange: "logs", type: ExchangeType.Fanout);
|
|
||||||
Queues.Add(exchange, new HashSet<string>());
|
|
||||||
}
|
|
||||||
if (queueName != null)
|
|
||||||
_channel.QueueDeclare(queue: queueName,
|
|
||||||
durable: true,
|
|
||||||
exclusive: false,
|
|
||||||
autoDelete: false,
|
|
||||||
arguments: null);
|
|
||||||
|
|
||||||
queueName = queueName ?? _channel.QueueDeclare().QueueName;
|
|
||||||
|
|
||||||
|
|
||||||
_channel.QueueBind(queue: queueName,
|
|
||||||
exchange: exchange,
|
|
||||||
routingKey: string.Empty);
|
|
||||||
|
|
||||||
var consumer = new EventingBasicConsumer(_channel);
|
|
||||||
consumer.Received += (model, ea) =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var message = Encoding.UTF8.GetString(ea.Body.ToArray());
|
|
||||||
handler(message);
|
|
||||||
_channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine(ex.Message);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
_channel.BasicConsume(queue: queueName,
|
|
||||||
autoAck: false,
|
|
||||||
consumer: consumer);
|
|
||||||
|
|
||||||
Queues[exchange].Add(queueName);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine(ex.Message);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
~Receiver() => Dispose();
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_connection.Dispose();
|
|
||||||
_channel.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<OutputType>Exe</OutputType>
|
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
|
||||||
<RootNamespace>EmitLog_</RootNamespace>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="RabbitMQ.Client" Version="6.8.1" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
@ -1,24 +0,0 @@
|
|||||||
using System.Text;
|
|
||||||
using RabbitMQ.Client;
|
|
||||||
|
|
||||||
var factory = new ConnectionFactory { HostName = "localhost" };
|
|
||||||
using var connection = factory.CreateConnection();
|
|
||||||
using var channel = connection.CreateModel();
|
|
||||||
|
|
||||||
channel.ExchangeDeclare(exchange: "logs", type: ExchangeType.Fanout);
|
|
||||||
|
|
||||||
var message = GetMessage(args);
|
|
||||||
var body = Encoding.UTF8.GetBytes(message);
|
|
||||||
channel.BasicPublish(exchange: "logs",
|
|
||||||
routingKey: string.Empty,
|
|
||||||
basicProperties: null,
|
|
||||||
body: body);
|
|
||||||
Console.WriteLine($" [x] Sent {message}");
|
|
||||||
|
|
||||||
Console.WriteLine(" Press [enter] to exit.");
|
|
||||||
Console.ReadLine();
|
|
||||||
|
|
||||||
static string GetMessage(string[] args)
|
|
||||||
{
|
|
||||||
return ((args.Length > 0) ? string.Join(" ", args) : "info: Hello World!");
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<OutputType>Exe</OutputType>
|
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="RabbitMQ.Client" Version="6.8.1" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
@ -1,32 +0,0 @@
|
|||||||
using System.Text;
|
|
||||||
using RabbitMQ.Client;
|
|
||||||
|
|
||||||
var factory = new ConnectionFactory { HostName = "localhost" };
|
|
||||||
using var connection = factory.CreateConnection();
|
|
||||||
using var channel = connection.CreateModel();
|
|
||||||
|
|
||||||
channel.QueueDeclare(queue: "task_queue",
|
|
||||||
durable: true,
|
|
||||||
exclusive: false,
|
|
||||||
autoDelete: false,
|
|
||||||
arguments: null);
|
|
||||||
|
|
||||||
var message = GetMessage(args);
|
|
||||||
var body = Encoding.UTF8.GetBytes(message);
|
|
||||||
|
|
||||||
var properties = channel.CreateBasicProperties();
|
|
||||||
properties.Persistent = true;
|
|
||||||
|
|
||||||
channel.BasicPublish(exchange: string.Empty,
|
|
||||||
routingKey: "task_queue",
|
|
||||||
basicProperties: properties,
|
|
||||||
body: body);
|
|
||||||
Console.WriteLine($" [x] Sent {message}");
|
|
||||||
|
|
||||||
Console.WriteLine(" Press [enter] to exit.");
|
|
||||||
Console.ReadLine();
|
|
||||||
|
|
||||||
static string GetMessage(string[] args)
|
|
||||||
{
|
|
||||||
return ((args.Length > 0) ? string.Join(" ", args) : "Hello World!");
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
**/.classpath
|
|
||||||
**/.dockerignore
|
|
||||||
**/.env
|
|
||||||
**/.git
|
|
||||||
**/.gitignore
|
|
||||||
**/.project
|
|
||||||
**/.settings
|
|
||||||
**/.toolstarget
|
|
||||||
**/.vs
|
|
||||||
**/.vscode
|
|
||||||
**/*.*proj.user
|
|
||||||
**/*.dbmdl
|
|
||||||
**/*.jfm
|
|
||||||
**/azds.yaml
|
|
||||||
**/bin
|
|
||||||
**/charts
|
|
||||||
**/docker-compose*
|
|
||||||
**/Dockerfile*
|
|
||||||
**/node_modules
|
|
||||||
**/npm-debug.log
|
|
||||||
**/obj
|
|
||||||
**/secrets.dev.yaml
|
|
||||||
**/values.dev.yaml
|
|
||||||
LICENSE
|
|
||||||
README.md
|
|
||||||
!**/.gitignore
|
|
||||||
!.git/HEAD
|
|
||||||
!.git/config
|
|
||||||
!.git/packed-refs
|
|
||||||
!.git/refs/heads/**
|
|
@ -1,20 +0,0 @@
|
|||||||
FROM mcr.microsoft.com/dotnet/runtime:6.0 AS base
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
|
|
||||||
ARG BUILD_CONFIGURATION=Release
|
|
||||||
WORKDIR /src
|
|
||||||
COPY ["Publisher.csproj", "."]
|
|
||||||
RUN dotnet restore "./Publisher.csproj"
|
|
||||||
COPY . .
|
|
||||||
WORKDIR "/src/."
|
|
||||||
RUN dotnet build "./Publisher.csproj" -c $BUILD_CONFIGURATION -o /app/build
|
|
||||||
|
|
||||||
FROM build AS publish
|
|
||||||
ARG BUILD_CONFIGURATION=Release
|
|
||||||
RUN dotnet publish "./Publisher.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
|
|
||||||
|
|
||||||
FROM base AS final
|
|
||||||
WORKDIR /app
|
|
||||||
COPY --from=publish /app/publish .
|
|
||||||
ENTRYPOINT ["dotnet", "Publisher.dll"]
|
|
@ -1,40 +0,0 @@
|
|||||||
using Publisher;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
var rabbitHost = Environment.GetEnvironmentVariable("RABBIT_HOST") ?? "localhost";
|
|
||||||
var rabbitUsername = Environment.GetEnvironmentVariable("RABBIT_USERNAME") ?? "user";
|
|
||||||
var rabbitPassword = Environment.GetEnvironmentVariable("RABBIT_PASSWORD") ?? "password";
|
|
||||||
var rabbitExchange = Environment.GetEnvironmentVariable("RABBIT_EXCHANGE") ?? "ReportIn";
|
|
||||||
|
|
||||||
var sender = new Sender(rabbitHost, rabbitUsername, rabbitPassword);
|
|
||||||
|
|
||||||
sender.AddExcange(rabbitExchange);
|
|
||||||
|
|
||||||
var rnd = new Random();
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
StringBuilder sb = new();
|
|
||||||
|
|
||||||
var type = rnd.Next();
|
|
||||||
switch (type%2)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
{
|
|
||||||
sb.Append($"Был запрошен отчет о данных под номером {rnd.Next(1000)}");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 1:
|
|
||||||
{
|
|
||||||
sb.Append($"Был запрошен отчет об ошибках под номером {rnd.Next(1000)}");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var text = sb.ToString();
|
|
||||||
Console.WriteLine($"Было опубликовано сообщение: {text}");
|
|
||||||
sender.PublishToExchange(rabbitExchange, text);
|
|
||||||
|
|
||||||
await Task.Delay(1000);
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
"profiles": {
|
|
||||||
"Publisher": {
|
|
||||||
"commandName": "Project"
|
|
||||||
},
|
|
||||||
"Container (Dockerfile)": {
|
|
||||||
"commandName": "Docker"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<OutputType>Exe</OutputType>
|
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
|
||||||
<DockerfileContext>.</DockerfileContext>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.20.1" />
|
|
||||||
<PackageReference Include="RabbitMQ.Client" Version="6.8.1" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
@ -1,9 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<PropertyGroup>
|
|
||||||
<ActiveDebugProfile>Container (Dockerfile)</ActiveDebugProfile>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
|
||||||
<DebuggerFlavor>ProjectDebugger</DebuggerFlavor>
|
|
||||||
</PropertyGroup>
|
|
||||||
</Project>
|
|
@ -1,25 +0,0 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
|
||||||
# Visual Studio Version 17
|
|
||||||
VisualStudioVersion = 17.10.35004.147
|
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Publisher", "Publisher.csproj", "{C23890FA-A4DD-4E5B-897F-37210C2F60CE}"
|
|
||||||
EndProject
|
|
||||||
Global
|
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
|
||||||
Debug|Any CPU = Debug|Any CPU
|
|
||||||
Release|Any CPU = Release|Any CPU
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
|
||||||
{C23890FA-A4DD-4E5B-897F-37210C2F60CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{C23890FA-A4DD-4E5B-897F-37210C2F60CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{C23890FA-A4DD-4E5B-897F-37210C2F60CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{C23890FA-A4DD-4E5B-897F-37210C2F60CE}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
|
||||||
HideSolutionNode = FALSE
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
|
||||||
SolutionGuid = {3BB20EB3-DE49-46CE-8C7A-D956E3DE90BC}
|
|
||||||
EndGlobalSection
|
|
||||||
EndGlobal
|
|
@ -1,69 +0,0 @@
|
|||||||
using RabbitMQ.Client;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Publisher
|
|
||||||
{
|
|
||||||
public class Sender : IDisposable
|
|
||||||
{
|
|
||||||
private readonly ConnectionFactory _connectionFactory;
|
|
||||||
private readonly IConnection _connection;
|
|
||||||
private readonly IModel _channel;
|
|
||||||
|
|
||||||
public HashSet<string> Exchanges { get; private set; } = new HashSet<string>();
|
|
||||||
|
|
||||||
public Sender(string brockerHost, string brockerUsername, string brockerPassword)
|
|
||||||
{
|
|
||||||
_connectionFactory = new ConnectionFactory() { HostName = brockerHost, UserName = brockerUsername, Password = brockerPassword };
|
|
||||||
_connection = _connectionFactory.CreateConnection();
|
|
||||||
_channel = _connection.CreateModel();
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool AddExcange(string exchange, string exchangeType = ExchangeType.Fanout)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_channel.ExchangeDeclare(exchange, exchangeType);
|
|
||||||
Exchanges.Add(exchange);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine(ex.Message);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool PublishToExchange(string exchange, string message)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!Exchanges.Contains(exchange))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var messageBody = Encoding.UTF8.GetBytes(message);
|
|
||||||
_channel.BasicPublish(exchange: exchange,
|
|
||||||
routingKey: string.Empty,
|
|
||||||
basicProperties: null,
|
|
||||||
body: messageBody);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine(ex.Message);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
~Sender() => Dispose();
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_connection.Dispose();
|
|
||||||
_channel.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
# Лабораторная работа 4
|
|
||||||
В рамках данной работы были реализованы несколько проектов, работающих с RabbitMQ.
|
|
||||||
## tutorial
|
|
||||||
Для каждого урока были созданы консольные проекты
|
|
||||||
### "Hello World!"
|
|
||||||
![Task 1](image-4.png)
|
|
||||||
### Work Queues
|
|
||||||
![Task 2](image-5.png)
|
|
||||||
### Publish/Subscribe
|
|
||||||
![Task 3](image-6.png)
|
|
||||||
## Описание
|
|
||||||
В качестве предметной области была выбрана система запросов отчета двух видов: отчета и ошибок.
|
|
||||||
## Запуск
|
|
||||||
Для запуска лабораторной работы необходимо иметь запущенный Docker на устройстве.
|
|
||||||
Необходимо перейти в папку, где располагается данный файл. Далее открыть терминал и ввести команду:
|
|
||||||
```
|
|
||||||
docker compose up -d --build
|
|
||||||
```
|
|
||||||
Порты для RabbitMQ были 8081 (для UI) и 5672.
|
|
||||||
## Анализ
|
|
||||||
Первоначальный вариант запуска предполагает, что имеется всего 2 потребителя:
|
|
||||||
1. Тратит на обработку сообщения 2-3 секунды
|
|
||||||
2. Тратит на обработку сообщения крайне малое время
|
|
||||||
Задержка при обработке понижает пропускную способность обработчика, что вызывает переполнение очереди. Это подтверждается скринами.
|
|
||||||
<br/>
|
|
||||||
![alt text](image.png)
|
|
||||||
<br/>
|
|
||||||
![alt text](image-1.png)
|
|
||||||
<br/>
|
|
||||||
Теперь запустим несколько обычных обработчиков. Очередь не переполнена постоянно, а периодически, соответственно обработчики вполне справляются с потоком сообщений и увеличение их количества позволит в принципе избавиться от переполнения
|
|
||||||
<br/>
|
|
||||||
![alt text](image-2.png)
|
|
||||||
<br/>
|
|
||||||
![alt text](image-3.png)
|
|
||||||
|
|
||||||
## Видеодемонстрация
|
|
||||||
Демонстрация: (https://drive.google.com/file/d/16gJMGbMKSFZ_I5gCzuDekpAqUrhbpFRA/view?usp=sharing) Стоит обратить внимание на то, что настройки docker compose файла не гарантируют верный порядок подъема контейнеров, из-за чего некоторые контейнеры пришлось перезапустить.
|
|
||||||
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
|||||||
using System.Text;
|
|
||||||
using RabbitMQ.Client;
|
|
||||||
using RabbitMQ.Client.Events;
|
|
||||||
|
|
||||||
var factory = new ConnectionFactory { HostName = "localhost" };
|
|
||||||
using var connection = factory.CreateConnection();
|
|
||||||
using var channel = connection.CreateModel();
|
|
||||||
|
|
||||||
channel.QueueDeclare(queue: "hello",
|
|
||||||
durable: false,
|
|
||||||
exclusive: false,
|
|
||||||
autoDelete: false,
|
|
||||||
arguments: null);
|
|
||||||
|
|
||||||
Console.WriteLine(" [*] Waiting for messages.");
|
|
||||||
|
|
||||||
var consumer = new EventingBasicConsumer(channel);
|
|
||||||
consumer.Received += (model, ea) =>
|
|
||||||
{
|
|
||||||
var body = ea.Body.ToArray();
|
|
||||||
var message = Encoding.UTF8.GetString(body);
|
|
||||||
Console.WriteLine($" [x] Received {message}");
|
|
||||||
};
|
|
||||||
channel.BasicConsume(queue: "hello",
|
|
||||||
autoAck: true,
|
|
||||||
consumer: consumer);
|
|
||||||
|
|
||||||
Console.WriteLine(" Press [enter] to exit.");
|
|
||||||
Console.ReadLine();
|
|
@ -1,14 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<OutputType>Exe</OutputType>
|
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="RabbitMQ.Client" Version="6.8.1" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
@ -1,31 +0,0 @@
|
|||||||
using System.Text;
|
|
||||||
using RabbitMQ.Client;
|
|
||||||
using RabbitMQ.Client.Events;
|
|
||||||
|
|
||||||
var factory = new ConnectionFactory { HostName = "localhost" };
|
|
||||||
using var connection = factory.CreateConnection();
|
|
||||||
using var channel = connection.CreateModel();
|
|
||||||
|
|
||||||
channel.ExchangeDeclare(exchange: "logs", type: ExchangeType.Fanout);
|
|
||||||
|
|
||||||
// declare a server-named queue
|
|
||||||
var queueName = channel.QueueDeclare().QueueName;
|
|
||||||
channel.QueueBind(queue: queueName,
|
|
||||||
exchange: "logs",
|
|
||||||
routingKey: string.Empty);
|
|
||||||
|
|
||||||
Console.WriteLine(" [*] Waiting for logs.");
|
|
||||||
|
|
||||||
var consumer = new EventingBasicConsumer(channel);
|
|
||||||
consumer.Received += (model, ea) =>
|
|
||||||
{
|
|
||||||
byte[] body = ea.Body.ToArray();
|
|
||||||
var message = Encoding.UTF8.GetString(body);
|
|
||||||
Console.WriteLine($" [x] {message}");
|
|
||||||
};
|
|
||||||
channel.BasicConsume(queue: queueName,
|
|
||||||
autoAck: true,
|
|
||||||
consumer: consumer);
|
|
||||||
|
|
||||||
Console.WriteLine(" Press [enter] to exit.");
|
|
||||||
Console.ReadLine();
|
|
@ -1,14 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<OutputType>Exe</OutputType>
|
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="RabbitMQ.Client" Version="6.8.1" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
@ -1,24 +0,0 @@
|
|||||||
using System.Text;
|
|
||||||
using RabbitMQ.Client;
|
|
||||||
|
|
||||||
var factory = new ConnectionFactory { HostName = "localhost" };
|
|
||||||
using var connection = factory.CreateConnection();
|
|
||||||
using var channel = connection.CreateModel();
|
|
||||||
|
|
||||||
channel.QueueDeclare(queue: "hello",
|
|
||||||
durable: false,
|
|
||||||
exclusive: false,
|
|
||||||
autoDelete: false,
|
|
||||||
arguments: null);
|
|
||||||
|
|
||||||
const string message = "Hello World!";
|
|
||||||
var body = Encoding.UTF8.GetBytes(message);
|
|
||||||
|
|
||||||
channel.BasicPublish(exchange: string.Empty,
|
|
||||||
routingKey: "hello",
|
|
||||||
basicProperties: null,
|
|
||||||
body: body);
|
|
||||||
Console.WriteLine($" [x] Sent {message}");
|
|
||||||
|
|
||||||
Console.WriteLine(" Press [enter] to exit.");
|
|
||||||
Console.ReadLine();
|
|
@ -1,14 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<OutputType>Exe</OutputType>
|
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="RabbitMQ.Client" Version="6.8.1" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
@ -1,39 +0,0 @@
|
|||||||
using System.Text;
|
|
||||||
using RabbitMQ.Client;
|
|
||||||
using RabbitMQ.Client.Events;
|
|
||||||
|
|
||||||
var factory = new ConnectionFactory { HostName = "localhost" };
|
|
||||||
using var connection = factory.CreateConnection();
|
|
||||||
using var channel = connection.CreateModel();
|
|
||||||
|
|
||||||
channel.QueueDeclare(queue: "task_queue",
|
|
||||||
durable: true,
|
|
||||||
exclusive: false,
|
|
||||||
autoDelete: false,
|
|
||||||
arguments: null);
|
|
||||||
|
|
||||||
channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false);
|
|
||||||
|
|
||||||
Console.WriteLine(" [*] Waiting for messages.");
|
|
||||||
|
|
||||||
var consumer = new EventingBasicConsumer(channel);
|
|
||||||
consumer.Received += (model, ea) =>
|
|
||||||
{
|
|
||||||
byte[] body = ea.Body.ToArray();
|
|
||||||
var message = Encoding.UTF8.GetString(body);
|
|
||||||
Console.WriteLine($" [x] Received {message}");
|
|
||||||
|
|
||||||
int dots = message.Split('.').Length - 1;
|
|
||||||
Thread.Sleep(dots * 1000);
|
|
||||||
|
|
||||||
Console.WriteLine(" [x] Done");
|
|
||||||
|
|
||||||
// here channel could also be accessed as ((EventingBasicConsumer)sender).Model
|
|
||||||
channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false);
|
|
||||||
};
|
|
||||||
channel.BasicConsume(queue: "task_queue",
|
|
||||||
autoAck: false,
|
|
||||||
consumer: consumer);
|
|
||||||
|
|
||||||
Console.WriteLine(" Press [enter] to exit.");
|
|
||||||
Console.ReadLine();
|
|
@ -1,14 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<OutputType>Exe</OutputType>
|
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="RabbitMQ.Client" Version="6.8.1" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
@ -1,59 +0,0 @@
|
|||||||
services:
|
|
||||||
rabbit:
|
|
||||||
image: rabbitmq:3.10.7-management
|
|
||||||
restart: always
|
|
||||||
ports:
|
|
||||||
- 5672:5672
|
|
||||||
- 8081:15672
|
|
||||||
environment:
|
|
||||||
RABBITMQ_DEFAULT_USER: admin
|
|
||||||
RABBITMQ_DEFAULT_PASS: admin
|
|
||||||
|
|
||||||
publisher:
|
|
||||||
build: ./Publisher/
|
|
||||||
restart: always
|
|
||||||
depends_on:
|
|
||||||
- rabbit
|
|
||||||
environment:
|
|
||||||
RABBIT_HOST: rabbit
|
|
||||||
RABBIT_USERNAME: admin
|
|
||||||
RABBIT_PASSWORD: admin
|
|
||||||
RABBIT_EXCHANGE: 'ReportIn'
|
|
||||||
|
|
||||||
concumer1:
|
|
||||||
build: ./ConsumerSimple/
|
|
||||||
restart: always
|
|
||||||
depends_on:
|
|
||||||
- rabbit
|
|
||||||
- publisher
|
|
||||||
environment:
|
|
||||||
RABBIT_HOST: rabbit
|
|
||||||
RABBIT_USERNAME: admin
|
|
||||||
RABBIT_PASSWORD: admin
|
|
||||||
RABBIT_EXCHANGE: 'ReportIn'
|
|
||||||
RABBIT_QUEUE: 'First'
|
|
||||||
|
|
||||||
concumer2:
|
|
||||||
build: ./ConsumerSimple/
|
|
||||||
restart: always
|
|
||||||
depends_on:
|
|
||||||
- rabbit
|
|
||||||
- publisher
|
|
||||||
environment:
|
|
||||||
RABBIT_HOST: rabbit
|
|
||||||
RABBIT_USERNAME: admin
|
|
||||||
RABBIT_PASSWORD: admin
|
|
||||||
RABBIT_EXCHANGE: 'ReportIn'
|
|
||||||
RABBIT_QUEUE: 'Second'
|
|
||||||
# concumer2:
|
|
||||||
# build: ./ConsumerDelay/
|
|
||||||
# restart: always
|
|
||||||
# depends_on:
|
|
||||||
# - rabbit
|
|
||||||
# - publisher
|
|
||||||
# environment:
|
|
||||||
# RABBIT_HOST: rabbit
|
|
||||||
# RABBIT_USERNAME: admin
|
|
||||||
# RABBIT_PASSWORD: admin
|
|
||||||
# RABBIT_EXCHANGE: 'ReportIn'
|
|
||||||
# RABBIT_QUEUE: 'Second'
|
|
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 136 KiB |
Before Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 16 KiB |
@ -1,114 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="AutoImportSettings">
|
|
||||||
<option name="autoReloadType" value="SELECTIVE" />
|
|
||||||
</component>
|
|
||||||
<component name="ChangeListManager">
|
|
||||||
<list default="true" id="c0e70306-e650-4c5f-8796-30690eb2be47" name="Changes" comment="">
|
|
||||||
<change afterPath="$PROJECT_DIR$/docker-compose.yml" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/nginx.conf" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/price_history_module/Dockerfile" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/price_history_module/src/main/java/ru/ulstu/price_history_module/config/AppConfig.java" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/price_history_module/src/main/java/ru/ulstu/price_history_module/controller/PriceHistoryController.java" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/price_history_module/src/main/java/ru/ulstu/price_history_module/model/PriceHistory.java" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/price_history_module/src/main/java/ru/ulstu/price_history_module/service/PriceHistoryService.java" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/price_history_module/src/main/java/ru/ulstu/price_history_module/service/dto/CreatePriceHistoryDto.java" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/product_module/Dockerfile" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/product_module/src/main/java/ru/ulstu/product_module/controller/ProductController.java" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/product_module/src/main/java/ru/ulstu/product_module/model/Product.java" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/product_module/src/main/java/ru/ulstu/product_module/service/ProductService.java" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/product_module/src/main/java/ru/ulstu/product_module/service/dto/CreateProductDto.java" afterDir="false" />
|
|
||||||
</list>
|
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
|
||||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
|
||||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
|
||||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
|
||||||
</component>
|
|
||||||
<component name="Git.Settings">
|
|
||||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/.." />
|
|
||||||
</component>
|
|
||||||
<component name="KubernetesApiPersistence">{}</component>
|
|
||||||
<component name="KubernetesApiProvider">{
|
|
||||||
"isMigrated": true
|
|
||||||
}</component>
|
|
||||||
<component name="ProjectColorInfo">{
|
|
||||||
"associatedIndex": 3
|
|
||||||
}</component>
|
|
||||||
<component name="ProjectId" id="2nKW7SdJYEDJy5g4bOXYcSQkE08" />
|
|
||||||
<component name="ProjectViewState">
|
|
||||||
<option name="hideEmptyMiddlePackages" value="true" />
|
|
||||||
<option name="showLibraryContents" value="true" />
|
|
||||||
</component>
|
|
||||||
<component name="PropertiesComponent">{
|
|
||||||
"keyToString": {
|
|
||||||
"Docker.docker-compose.yml.price: Compose Deployment.executor": "Run",
|
|
||||||
"Docker.docker-compose.yml: Compose Deployment.executor": "Run",
|
|
||||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
|
||||||
"git-widget-placeholder": "emelaynov__artem__lab__3",
|
|
||||||
"kotlin-language-version-configured": "true",
|
|
||||||
"last_opened_file_path": "/home/forever/УлГТУ/Распределенные вычисления и приложения/DAS_2024_1/emelaynov_artem_lab_3",
|
|
||||||
"node.js.detected.package.eslint": "true",
|
|
||||||
"node.js.detected.package.tslint": "true",
|
|
||||||
"node.js.selected.package.eslint": "(autodetect)",
|
|
||||||
"node.js.selected.package.tslint": "(autodetect)",
|
|
||||||
"nodejs_package_manager_path": "npm",
|
|
||||||
"vue.rearranger.settings.migration": "true"
|
|
||||||
}
|
|
||||||
}</component>
|
|
||||||
<component name="RunManager" selected="Docker.docker-compose.yml: Compose Deployment">
|
|
||||||
<configuration default="true" type="docker-deploy" factoryName="docker-compose.yml" temporary="true">
|
|
||||||
<deployment type="docker-compose.yml" />
|
|
||||||
<method v="2" />
|
|
||||||
</configuration>
|
|
||||||
<configuration name="docker-compose.yml: Compose Deployment" type="docker-deploy" factoryName="docker-compose.yml" temporary="true" server-name="Docker">
|
|
||||||
<deployment type="docker-compose.yml">
|
|
||||||
<settings>
|
|
||||||
<option name="sourceFilePath" value="docker-compose.yml" />
|
|
||||||
</settings>
|
|
||||||
</deployment>
|
|
||||||
<method v="2" />
|
|
||||||
</configuration>
|
|
||||||
<configuration name="docker-compose.yml.price: Compose Deployment" type="docker-deploy" factoryName="docker-compose.yml" temporary="true" server-name="Docker">
|
|
||||||
<deployment type="docker-compose.yml">
|
|
||||||
<settings>
|
|
||||||
<option name="services">
|
|
||||||
<list>
|
|
||||||
<option value="price" />
|
|
||||||
</list>
|
|
||||||
</option>
|
|
||||||
<option name="sourceFilePath" value="docker-compose.yml" />
|
|
||||||
</settings>
|
|
||||||
</deployment>
|
|
||||||
<method v="2" />
|
|
||||||
</configuration>
|
|
||||||
<recent_temporary>
|
|
||||||
<list>
|
|
||||||
<item itemvalue="Docker.docker-compose.yml: Compose Deployment" />
|
|
||||||
<item itemvalue="Docker.docker-compose.yml.price: Compose Deployment" />
|
|
||||||
</list>
|
|
||||||
</recent_temporary>
|
|
||||||
</component>
|
|
||||||
<component name="SharedIndexes">
|
|
||||||
<attachedChunks>
|
|
||||||
<set>
|
|
||||||
<option value="bundled-jdk-9823dce3aa75-28b599e66164-intellij.indexing.shared.core-IU-242.22855.74" />
|
|
||||||
<option value="bundled-js-predefined-d6986cc7102b-5c90d61e3bab-JavaScript-IU-242.22855.74" />
|
|
||||||
</set>
|
|
||||||
</attachedChunks>
|
|
||||||
</component>
|
|
||||||
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
|
||||||
<component name="TaskManager">
|
|
||||||
<task active="true" id="Default" summary="Default task">
|
|
||||||
<changelist id="c0e70306-e650-4c5f-8796-30690eb2be47" name="Changes" comment="" />
|
|
||||||
<created>1728722079988</created>
|
|
||||||
<option name="number" value="Default" />
|
|
||||||
<option name="presentableId" value="Default" />
|
|
||||||
<updated>1728722079988</updated>
|
|
||||||
<workItem from="1728722081004" duration="8714000" />
|
|
||||||
</task>
|
|
||||||
<servers />
|
|
||||||
</component>
|
|
||||||
<component name="TypeScriptGeneratedFilesManager">
|
|
||||||
<option name="version" value="3" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
@ -1,30 +0,0 @@
|
|||||||
## Задание
|
|
||||||
|
|
||||||
1. Создать 2 микросервиса, реализующих CRUD на связанных сущностях.
|
|
||||||
2. Реализовать механизм синхронного обмена сообщениями между микросервисами.
|
|
||||||
3. Реализовать шлюз на основе прозрачного прокси-сервера nginx.
|
|
||||||
|
|
||||||
Вариант: Продукты и история цен на них
|
|
||||||
|
|
||||||
## Выполнение
|
|
||||||
Были написаны два сервиса на языке java, фреймворк Spring:
|
|
||||||
* Сервис price_module, хранящий данные о продуктах и реализующий CRUD операции с ними через HTTP запросы.
|
|
||||||
* Сервис price_history_module, хранящий данные об истории цен на продукты и реализующий CRUD операции с ними через HTTP запросы.
|
|
||||||
|
|
||||||
Сервисы синхронно сообщены - сервис истории цен при создании записи с ценой, посылает сообщение продукту на связывание.
|
|
||||||
|
|
||||||
Для сервисов прописаны файлы Dockerfile, описывающие создание контейнеров:
|
|
||||||
* Оба контейнера проявляют порты, на которых работает приложение: 8080 для продуктов и 8081 для истории цен.
|
|
||||||
* Выбирается рабочая директория /app и туда копируются файлы скриптов.
|
|
||||||
* Командой запускаются сами скрипты.
|
|
||||||
|
|
||||||
Общий yaml-файл развёртки был настроен следующим образом:
|
|
||||||
* блок services, где перечислены разворачиваемые сервисы.
|
|
||||||
* для каждого сервиса прописан build, где объявляется его папка и докерфайл создания и зависимости.
|
|
||||||
* для сервиса nginx прописан порт для отображения вовне.
|
|
||||||
|
|
||||||
## Результат
|
|
||||||
Демонстрация работы в видео.
|
|
||||||
|
|
||||||
## Ссылка на видео
|
|
||||||
https://drive.google.com/file/d/1tH7FwSu_VWJ5SKJBXm3zPKbxTAKVUFxb/view?usp=sharing
|
|
@ -1,37 +0,0 @@
|
|||||||
version: '3'
|
|
||||||
|
|
||||||
services:
|
|
||||||
nginx:
|
|
||||||
image: nginx:latest
|
|
||||||
container_name: nginx
|
|
||||||
ports:
|
|
||||||
- "80:80"
|
|
||||||
volumes:
|
|
||||||
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
|
||||||
depends_on:
|
|
||||||
- price
|
|
||||||
- product
|
|
||||||
networks:
|
|
||||||
- app-network
|
|
||||||
|
|
||||||
product:
|
|
||||||
build:
|
|
||||||
context: ./product_module
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
ports:
|
|
||||||
- "8080:8080"
|
|
||||||
networks:
|
|
||||||
- app-network
|
|
||||||
|
|
||||||
price:
|
|
||||||
build:
|
|
||||||
context: ./price_history_module
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
ports:
|
|
||||||
- "8081:8081"
|
|
||||||
networks:
|
|
||||||
- app-network
|
|
||||||
|
|
||||||
networks:
|
|
||||||
app-network:
|
|
||||||
driver: bridge
|
|
@ -1,21 +0,0 @@
|
|||||||
http {
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
listen [::]:80;
|
|
||||||
server_name localhost;
|
|
||||||
|
|
||||||
# Прокси для ProductService
|
|
||||||
location /product/ {
|
|
||||||
proxy_pass http://product:8080;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Прокси для PriceHistoryService
|
|
||||||
location /price-history/ {
|
|
||||||
proxy_pass http://price:8081;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
events {
|
|
||||||
worker_connections 1024;
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
HELP.md
|
|
||||||
.gradle
|
|
||||||
build/
|
|
||||||
!gradle/wrapper/gradle-wrapper.jar
|
|
||||||
!**/src/main/**/build/
|
|
||||||
!**/src/test/**/build/
|
|
||||||
|
|
||||||
### STS ###
|
|
||||||
.apt_generated
|
|
||||||
.classpath
|
|
||||||
.factorypath
|
|
||||||
.project
|
|
||||||
.settings
|
|
||||||
.springBeans
|
|
||||||
.sts4-cache
|
|
||||||
bin/
|
|
||||||
!**/src/main/**/bin/
|
|
||||||
!**/src/test/**/bin/
|
|
||||||
|
|
||||||
### IntelliJ IDEA ###
|
|
||||||
.idea
|
|
||||||
*.iws
|
|
||||||
*.iml
|
|
||||||
*.ipr
|
|
||||||
out/
|
|
||||||
!**/src/main/**/out/
|
|
||||||
!**/src/test/**/out/
|
|
||||||
|
|
||||||
### NetBeans ###
|
|
||||||
/nbproject/private/
|
|
||||||
/nbbuild/
|
|
||||||
/dist/
|
|
||||||
/nbdist/
|
|
||||||
/.nb-gradle/
|
|
||||||
|
|
||||||
### VS Code ###
|
|
||||||
.vscode/
|
|
@ -1,7 +0,0 @@
|
|||||||
FROM openjdk:17-jdk-slim
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
COPY build/libs/price_history_module-0.0.1-SNAPSHOT.jar /app/price.jar
|
|
||||||
|
|
||||||
ENTRYPOINT ["java", "-jar", "price.jar"]
|
|