Compare commits

..

No commits in common. "main" and "kutygin_andrey_lab_3" have entirely different histories.

66 changed files with 0 additions and 1021 deletions

View File

@ -1,3 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JpaBuddyIdeaProjectConfig">
<option name="renamerInitialized" value="true" />
</component>
</project>

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="18" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
<component name="ProjectType">
<option name="id" value="jpab" />
</component>
</project>

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/kutygin_andrey_lab_1.iml" filepath="$PROJECT_DIR$/kutygin_andrey_lab_1.iml" />
</modules>
</component>
</project>

View File

@ -1,63 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ChangeListManager">
<list default="true" id="2825a2d7-cbe6-410f-9785-96603cbb0f02" name="Changes" comment="" />
<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="MarkdownSettingsMigration">
<option name="stateVersion" value="1" />
</component>
<component name="ProjectId" id="2aWZgD9jVzSrrT33mt6jGLtpCOt" />
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent"><![CDATA[{
"keyToString": {
"RunOnceActivity.OpenProjectViewOnStart": "true",
"RunOnceActivity.ShowReadmeOnStart": "true",
"project.structure.last.edited": "Modules",
"project.structure.proportion": "0.15",
"project.structure.side.proportion": "0.2"
}
}]]></component>
<component name="RecentsManager">
<key name="MoveFile.RECENT_KEYS">
<recent name="C:\Users\kutyg\Downloads\pibd-22-internet-programming-Lab5 (1)\kutygin_andrey_lab_1" />
</key>
</component>
<component name="RunManager">
<configuration name="docker-compose.yml.rabbitmq: 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="rabbitmq" />
</list>
</option>
<option name="sourceFilePath" value="docker-compose.yml" />
</settings>
</deployment>
<method v="2" />
</configuration>
<recent_temporary>
<list>
<item itemvalue="Docker.docker-compose.yml.rabbitmq: Compose Deployment" />
</list>
</recent_temporary>
</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="2825a2d7-cbe6-410f-9785-96603cbb0f02" name="Changes" comment="" />
<created>1704436409086</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1704436409086</updated>
</task>
<servers />
</component>
</project>

View File

@ -1,28 +0,0 @@
**Задание**
***
Развернуть не менее 3х сервисов через docker-compose.
**Выполнение**
***
Было выбрано три сервиса: RabbitMQ, MediaWiki, WordPress.
Описание сервисов:
- "rabbitmq": использует образ rabbitmq:3.12.8-management и открывает порты 5672 и 15672 для доступа к RabbitMQ и его управляющему интерфейсу.
- "mediawiki": использует образ mediawiki и открывает порт 8082 для доступа к серверу Mediawiki.
- "wordpress": использует образ wordpress и открывает порт 8083 для доступа к серверу Wordpress.
Описание томов:
- "rabbitmq-data": том для хранения данных RabbitMQ.
- "mediawiki-data": том для хранения данных Mediawiki.
- "wordpress-data": том для хранения данных Wordpress.
**Результаты:**
***
![mediawiki.png](screenshots/mediawiki.png)
![rabbitmq.png](screenshots/rabbitmq.png)
![wordpress.png](screenshots/wordpress.png)
**Видео:**
[![Видео по лабораторной](https://avatars.mds.yandex.net/i?id=39a897a792179979ea684bfffbe0ca3ce053731c-10928048-images-thumbs&n=13)](https://disk.yandex.ru/i/-9wvRKd04dLa8w)
Нужно кликнуть на jpg, чтобы открылось

View File

@ -1,27 +0,0 @@
services:
rabbitmq:
image: rabbitmq:3.12.8-management
ports:
- 5672:5672
- 15672:15672
volumes:
- rabbitmq-data:/var/lib/rabbitmq
mediawiki:
image: mediawiki
ports:
- 8082:80
volumes:
- mediawiki-data:/var/files/mediawiki
wordpress:
image: wordpress
ports:
- 8083:80
volumes:
- wordpress-data:/var/files/wordpress
volumes:
rabbitmq-data:
mediawiki-data:
wordpress-data:

View File

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

View File

@ -1,3 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JpaBuddyIdeaProjectConfig">
<option name="renamerInitialized" value="true" />
</component>
</project>

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" languageLevel="JDK_18" default="true" project-jdk-name="18" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
<component name="ProjectType">
<option name="id" value="jpab" />
</component>
</project>

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/kutygin_andrey_lab_2.iml" filepath="$PROJECT_DIR$/kutygin_andrey_lab_2.iml" />
</modules>
</component>
</project>

View File

@ -1,121 +0,0 @@
**Задание**
***
Цель: изучение техники создания простого распределённого приложения.
**Задачи**
***
Согласно варианту (0 и 1) разработать два приложения такие, что результат первого является исходными данными для второго.
Изучить файлы сборки образов docker и разработать их для созданных приложений.
Собрать файл docker-compose.yml для запуска приложений. Разобраться с монтированием каталогов из хост-системы.
Правильно закоммитить результат без лишних файлов.
Оформить pull request по правилам и отправить его на проверку.
**Ход работы**
***
**Разворачивание сервисов:**
***
Были разработаны два приложения на java:
worker-1 - Формирует файл /var/result/data.txt из файла, где было найдено самое большое число /var/data.
worker-2 - Ищет набольшее число из файла /var/result/data.txt и сохраняет его вторую степень в /var/result/result.txt.
**Исходные файлы**
Исходные файлы содержат целые числа.
В /var/result/data.txt проверяются числа из каждого файла и выбирается самое большое
**Firsttxt.txt:**
1
2
3
4
5
**Secondtxt.txt**
1
2
3
**Thirdtxt.txt**
1
2
3
4
5
6
7
8
9
10
В /var/result/result.txt записывается число 100 - квадрат наибольшего числа - 10
**Dockerfile**
Для данной работы были созданы идентичные докер-файлы в обоих проектах.
````
FROM openjdk:17
RUN mkdir /var/data
RUN mkdir /var/result
WORKDIR /app
COPY src /app/src
RUN javac /app/src/Main.java
CMD ["java", "-cp", "/app/src", "Main"]
````
FROM - выбор базового образа
RUN - создание директории внутри контейнера
WORKDIR - установка рабочей директории для последующих команд
COPY - копирование содержимого директории внутрь контейнера
RUN - компиляция исходного кода Main.java внутри контейнера
CMD - определение команды, которая выполняется при запуске контейнера. В данном случае происходит запуск программы на java и указывается пусть до Main.java
**docker-compose.yml**
````
version: "3" #формат конфигурации Docker Compose версии 3
services: #определение сервисов
worker1:
build:
context: /worker-1 #путь к контексту сборки
dockerfile: Dockerfile #имя докерфайла
volumes:
- .\var\data:/var/data #том для папки файлов
- .\var\result:/var/result #том для папки результатов
worker2:
- depends_on: #зависимость: worker2 не будет запущен, пока worker1 не завершит свой запуск
worker1
build:
context: /worker-2 #путь к контексту сборки
- dockerfile: Dockerfile #имя докерфайла
- volumes:
- .\var\result:/var/data #том для папки файлов
- .\var\result:/var/result #том для папки результатов
````
Видео: https://disk.yandex.ru/d/jpeOKQ_PAO0c0Q

View File

@ -1,18 +0,0 @@
version: "3" #формат конфигурации Docker Compose версии 3
services: #определение сервисов
worker1:
build:
context: /worker_1 #путь к контексту сборки
dockerfile: Dockerfile #имя докерфайла
volumes:
- .\var\data:/var/data #том для папки файлов
- .\var\result:/var/result #том для папки результатов
worker2:
depends_on: #зависимость: worker2 не будет запущен, пока worker1 не завершит свой запуск
- worker1
build:
context: /worker_2 #путь к контексту сборки
dockerfile: Dockerfile #имя докерфайла
volumes:
- .\var\result:/var/data #том для папки файлов
- .\var\result:/var/result #том для папки результатов

View File

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@ -1,5 +0,0 @@
1
2
3
4
5

View File

@ -1,3 +0,0 @@
1
2
3

View File

@ -1,10 +0,0 @@
1
2
3
4
5
6
7
8
9
10

View File

@ -1,10 +0,0 @@
1
2
3
4
5
6
7
8
9
10

View File

@ -1 +0,0 @@
100.0

View File

@ -1,11 +0,0 @@
FROM openjdk:17
RUN mkdir /var/data
RUN mkdir /var/result
WORKDIR /app
COPY src /app/src
RUN javac /app/src/Main.java
CMD ["java", "-cp", "/app/src", "Main"]

View File

@ -1,40 +0,0 @@
import java.io.*;
import java.nio.file.*;
//Ищет в каталоге /var/data самый большой по объёму файл и перекладывает его в /var/result/data.txt.
public class Main {
private static Path findLargestFile(DirectoryStream<Path> stream) throws IOException {
long maxSize = 0;
Path largestFile = null;
for (Path file : stream) {
long size = Files.size(file);
if (size > maxSize) {
maxSize = size;
largestFile = file;
}
}
return largestFile;
}
public static void main(String[] args) {
Path dataDir = Path.of("/var/data");
Path resultDir = Path.of("/var/result");
try (DirectoryStream<Path> stream = Files.newDirectoryStream(dataDir)) {
Path largestFile = findLargestFile(stream);
if (largestFile != null) {
Files.createFile(resultDir.resolve("data.txt"));
Files.copy(largestFile, resultDir.resolve("data.txt"), StandardCopyOption.REPLACE_EXISTING);
System.out.println(largestFile.getFileName() + " перемещён");
} else {
System.out.println("Файл не найден");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@ -1,11 +0,0 @@
FROM openjdk:17
RUN mkdir /var/data
RUN mkdir /var/result
WORKDIR /app
COPY src /app/src
RUN javac /app/src/Main.java
CMD ["java", "-cp", "/app/src", "Main"]

View File

@ -1,50 +0,0 @@
import java.io.*;
import java.nio.file.*;
import java.util.*;
//Ищет набольшее число из файла /var/data/data.txt и сохраняет его вторую степень в /var/result/result.txt.
public class Main {
public static void main(String[] args) {
Path dataFile = Path.of("/var/result/data.txt");
Path resultFile = Path.of("/var/result/result.txt");
try {
if (!Files.exists(dataFile)) {
System.out.println("Файл data.txt не существует");
return;
}
List<Integer> numbers = readNumbersFromFile(dataFile);
int maxNumber = findMaxNumber(numbers);
try (BufferedWriter writer = Files.newBufferedWriter(resultFile)) {
writer.write(String.valueOf(Math.pow(maxNumber,2)));
}
System.out.println("квадрат наибольшего числа " + Math.pow(maxNumber,2));
} catch (IOException e) {
e.printStackTrace();
}
}
private static List<Integer> readNumbersFromFile(Path dataFile) throws IOException {
List<Integer> numbers = new ArrayList<>();
try (BufferedReader reader = Files.newBufferedReader(dataFile)) {
String line;
while ((line = reader.readLine()) != null) {
numbers.add(Integer.parseInt(line));
}
}
return numbers;
}
private static int findMaxNumber(List<Integer> numbers) {
int maxNumber = Integer.MIN_VALUE;
for (int number : numbers) {
if (number > maxNumber) {
maxNumber = number;
}
}
return maxNumber;
}
}

View File

@ -1,45 +0,0 @@
# Лабораторная работа 4. Работа с брокером сообщений
### Задание на лабораторную работу
1. Установить брокер сообщений RabbitMQ.
2. Пройти уроки 1, 2 и 3 из RabbitMQ Tutorials на любом языке программирования.
3. Продемонстрировать работу брокера сообщений.
***
### Описание работы
Были разработаны 3 приложения на *java*:
1. **Publisher**. Программа, которая создаёт один *exchange* с типом *fanout* и раз в секунду генерирует сообщение.
![](images/publisher.jpg)
2. **Consumer1**. Программа, которая создаёт под себя отдельную не анонимную очередь (*queue1*), создаёт *binding* на
*exchange* и начинает принимать сообщения. Программа обрабатывает сообщения 3 секунды.
![](images/consumer1.jpg)
3. **Consumer2**. Аналогично *Consumer1*, только сообщения обрабатываются моментально и имя очереди (*queue2*)
отличается от *Consumer1*.
![](images/consumer2.jpg)
***
### Отчеты
***RabbitMQ Management UI***
![](images/result1.jpg)
![](images/result2.jpg)
***Exchange***
![](images/result3.jpg)
***Очередь Consumer1***
![](images/queue1.jpg)
***Очередь Consumer2***
![](images/queue2.jpg)
### Ссылка на видео:
https://drive.google.com/file/d/19OdXnNM29SjayVZJ1qdsrMFTHkAUGxZf/view?usp=sharing

View File

@ -1,50 +0,0 @@
package org.example;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DeliverCallback;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
public class Consumer1 {
private static final String EXCHANGE_NAME = "messages";
private static final String QUEUE_NAME = "queue1";
public static void main(String[] argv) {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
factory.setPort(5672);
factory.setUsername("guest");
factory.setPassword("guest");
try (Connection connection = factory.newConnection();
Channel channel = connection.createChannel()) {
// Создание не анонимной очереди с уникальным именем
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");
System.out.println(LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")) + " Consumer 1 ожидает сообщений...");
// Обработка сообщений
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
String message = new String(delivery.getBody());
System.out.println(LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")) + " Consumer 1 обрабатывает " + message);
try {
Thread.sleep(3000); // Обработка 3 секунды
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")) + " Consumer 1 получил " + message);
};
channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> {});
while (true) {
// Поддержание работы приложения
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@ -1,44 +0,0 @@
package org.example;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DeliverCallback;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
public class Consumer2 {
private static final String EXCHANGE_NAME = "messages";
private static final String QUEUE_NAME = "queue2";
public static void main(String[] argv) {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
factory.setPort(5672);
factory.setUsername("guest");
factory.setPassword("guest");
try (Connection connection = factory.newConnection();
Channel channel = connection.createChannel()) {
// Создание не анонимной очереди с уникальным именем
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");
System.out.println(LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")) + " Consumer 2 ожидает сообщений...");
// Обработка сообщений
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
String message = new String(delivery.getBody());
// Обработка моментально, без задержки
System.out.println(LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")) + " Consumer 2 получил " + message);
};
channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> {});
while (true) {
// Поддержание работы приложения
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@ -1,33 +0,0 @@
package org.example;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
public class Publisher {
private static final String EXCHANGE_NAME = "messages";
public static void main(String[] args) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
factory.setPort(5672);
factory.setUsername("guest");
factory.setPassword("guest");
try (Connection connection = factory.newConnection();
Channel channel = connection.createChannel()) {
channel.exchangeDeclare(EXCHANGE_NAME, "fanout");
while (true) {
String message = "сообщение от пользователя c id = " + Math.round((Math.random() * 100));
channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes());
System.out.println(LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")) + " Отправлено: " + message);
Thread.sleep(1000); // Пауза в 1 секунду
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

View File

@ -1,57 +0,0 @@
# Лабораторная работа №4 - Работа с брокером сообщений
## Задание
#### Цель:
Изучение проектирования приложений при помощи брокера сообщений.
#### Задачи:
* Установить брокер сообщений RabbitMQ.
* Пройти уроки 1, 2 и 3 из RabbitMQ Tutorials на любом языке программирования.
* Продемонстрировать работу брокера сообщений.
### Классы:
&nbsp;1. ```Publisher``` - класс, отвечающий за отправку сообщений
&nbsp;2. ```Consumer1``` - класс, отвечающий за принятие и обработку сообщений за задержкой 3 секунды
&nbsp;2. ```Consumer2``` - класс, отвечающий за принятие и обработку сообщений без задержек
#### Ход работы:
На компьютер был установлен брокер сообщений ```RabbitMQ```, после чего все три класса программы были одновременно запущены.
## Работа программы:
Класс ```Publisher``` успешно осуществляет отправку сообщений своим клиентам.
![](Publisher.png "")
Класс ```Consumer1``` осуществляет принятие и обработку сообщений с задержкой в 3 секунды, это можно заметить на видео.
![](Consumer1.png "")
Класс ```Consumer2``` мгновенно осуществляет принятие и обработку сообщений.
![](Consumer2.png "")
## Работа с RabbitMQ Management UI
![](overview.png "")
### Очередь ```Consumer1```
![](qConsumer1.png "")
### Очередь ```Consumer2```
![](qConsumer2.png "")
### Exchange
![](ex.png "")
# Youtube
https://youtu.be/dw7j0WgDmS8

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

View File

@ -1,42 +0,0 @@
package org.example;
import com.rabbitmq.client.*;
public class Consumer1 {
private static final String QUEUE_NAME = "queue1";
private static final String EXCHANGE_NAME = "exchange";
public static void main(String[] args) throws Exception {
try {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
String message = new String(delivery.getBody());
try {
System.out.println("Consumer1 received" + message);
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(" Consumer1 processed the following message: " + message);
};
channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> {});
System.out.println("Consumer1 is waiting for messages");
while (true) {
// Поддержание работы приложения
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@ -1,37 +0,0 @@
package org.example;
import com.rabbitmq.client.*;
public class Consumer2 {
private static final String EXCHANGE_NAME = "exchange";
private static final String QUEUE_NAME = "queue2";
public static void main(String[] args) throws Exception {
try {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
String message = new String(delivery.getBody());
System.out.println("Consumer2 received" + message);
// моментальная обработка сообщений
System.out.println("Consumer2 processed the following message: " + message);
};
channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> {});
System.out.println("Consumer2 is waiting for messages");
while (true) {
// Поддержание работы приложения
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@ -1,35 +0,0 @@
package org.example;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.util.Random;
public class Publisher {
private static final String EXCHANGE_NAME = "exchange";
public static void main(String[] args) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
try (Connection connection = factory.newConnection();
Channel channel = connection.createChannel()) {
channel.exchangeDeclare(EXCHANGE_NAME, "fanout");
while (true) {
String message = generateMessage(); // Генерация сообщения для журнала событий
channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes());
System.out.println("Sent: " + message);
Thread.sleep(1000); // Ожидание 1 секунду
}
} catch (Exception e) {
e.printStackTrace();
}
}
private static String generateMessage() {
Random random = new Random();
return "message №" + random.nextInt(100) + 1;
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

View File

@ -1,42 +0,0 @@
## Задание
Развернуть два взаимосвязанных сервиса по варианту:
Вариант № 4 для первой программы:
* Сервис формирует файл /var/result/data.txt так, что каждая строка файла - количество символов в именах файлов из каталога /var/data.
Вариант № 2 для второй программы:
* Сервис ищет наименьшее число из файла /var/data/data.txt и сохраняет его третью степень в /var/result/result.txt.
## Выполнение
Были написаны два сервиса на языке python с использованием технологии flask.
Они выводят на страницу кнопки, при нажатии на которые происходит соответствующие действия по заданию
Для сервисов прописаны файлы Dockerfile, описывающие создание контейнеров:
* Для обоих контейнеров выбирается Python 11
* На оба контейнера пробрасываются порты, на которых работает приложение: 8081 для первого и 8082 для второго
* Внутри контейнеров создаются папки /work для файлов скриптов, папки /var/result, /var/data для обоих сервисов
* В оба контейнера устанавливается фреймворк Flask
* Выбирается рабочая директория /work и туда копируются файлы скриптов
* Командой запускаются сами скрипты
Общий yml-файл настроен следующим образом:
* блок services, где перечислены разворачиваемые сервисы.
* для каждого сервиса прописан build, где обозначается его папка
* для каждого сервиса прописано пробрасывание портов на хостовую машину
* для каждого сервиса прописано отображение внутриконтейнерных папок на хостовые
## Результат
Пример выполнения:
Исходные данные: четыре файла в папке /var/data с разным по длине названием
Ход работы: нажатие кнопок на странице первого сервиса, потом - второго
Созданные контейнеры:
![Контейнеры](images/containers.png)
Страница первого задания:
![Страница первого задания](images/exercise1.png)
Выходные данные при выполнении второго задания:
![Второе задание. Результат](images/exercise2.png)
## Ссылка на видео
https://youtu.be/CEAAr0xolxM

View File

@ -1,19 +0,0 @@
version: '3'
services:
service1:
build:
context: ./service1
ports:
- "8081:8081"
volumes:
- .\var\data:/var/data
- .\var\result:/var/result
service2:
build:
context: ./service2
ports:
- "8082:8082"
volumes:
- ./var/result:/var/result

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

View File

@ -1,15 +0,0 @@
FROM python:3.11
ENV LISTEN_PORT=8081
EXPOSE 8081
RUN ["mkdir", "/work"]
RUN ["mkdir", "/var/data"]
RUN ["mkdir", "/var/result"]
RUN pip install Flask
WORKDIR /work
COPY index.html service1.py ./
CMD ["python", "service1.py"]

View File

@ -1,12 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Сервис № 1</title>
</head>
<body>
<form action="http://localhost:8081/ex">
<input type="submit" value="Выполнить 1ое задание"/>
</form>
</body>
</html>

View File

@ -1,39 +0,0 @@
from flask import Flask, redirect, render_template
import os
app = Flask(__name__, template_folder='')
@app.route('/')
def home():
return render_template("index.html")
@app.route('/ex')
def do():
current_directory = os.getcwd()
directory_elements = current_directory.split(os.path.sep) # Разделяем по разделителю каталогов
cur_d = os.path.sep.join(directory_elements[:-1])
data_dir = cur_d + '/var/data'
path_result_file = cur_d + '/var/result/data.txt'
try:
# Получаем список файлов в указанном каталоге
files = os.listdir(data_dir)
# Формируем путь к каждому файлу и считаем количество символов в именах
characters_count_list = [len(file) for file in files]
# Пишем результат в файл data.txt
with open(path_result_file, 'w') as result_file:
for count in characters_count_list:
result_file.write(f'{count}\n')
print(f'Файл успешно создан.')
except Exception as e:
print(f'Произошла ошибка: {e}')
return redirect("/")
app.run(host='0.0.0.0', port=8081)

View File

@ -1,14 +0,0 @@
FROM python:3.11
ENV LISTEN_PORT=8082
EXPOSE 8082
RUN ["mkdir", "/work"]
RUN ["mkdir", "/var/result"]
RUN pip install Flask
WORKDIR /work
COPY index.html result.html service2.py ./
CMD ["python", "service2.py"]

View File

@ -1,12 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Сервис № 2</title>
</head>
<body>
<form action="http://localhost:8082/ex">
<input type="submit" value="Выполнить 2ое задание"/>
</form>
</body>
</html>

View File

@ -1,10 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Результат работы</title>
</head>
<body>
<h2>Результат: {{num}}</h2>
</body>
</html>

View File

@ -1,43 +0,0 @@
import os
from flask import Flask, render_template
app = Flask(__name__, template_folder='')
@app.route('/')
def home():
return render_template("index.html")
@app.route('/ex')
def do():
current_directory = os.getcwd()
directory_elements = current_directory.split(os.path.sep) # Разделяем по разделителю каталогов
cur_d = os.path.sep.join(directory_elements[:-1])
path_data_file = cur_d + '/var/result/data.txt'
path_result_file = cur_d + '/var/result/result.txt'
min_number = 0
try:
# Чтение чисел из файла
with open(path_data_file, 'r') as file:
numbers = [float(line.strip()) for line in file]
# Поиск минимального числа
min_number = min(numbers)
# Возведение минимального числа в третью степень
result = min_number ** 3
# Запись результата в файл
with open(path_result_file, 'w') as result_file:
result_file.write(str(result))
print(f'Наименьшее число из файла {path_data_file} в третьей степени сохранено в {path_result_file}.')
except Exception as e:
print(f'Произошла ошибка: {e}')
return render_template("result.html", num=min_number)
app.run(host='0.0.0.0', port=8082)