diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..473874b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,57 @@
+################################################################################
+# Данный GITIGNORE-файл был автоматически создан Microsoft(R) Visual Studio.
+################################################################################
+
+/.vs/DAS_2024_1
+/.vs
+/aleikin_artem_lab_3/.vs
+/aleikin_artem_lab_3/ProjectEntityProject/bin/Debug/net8.0
+/aleikin_artem_lab_3/ProjectEntityProject/obj
+/aleikin_artem_lab_3/TaskProject/bin/Debug/net8.0
+/aleikin_artem_lab_3/TaskProject/obj/Container
+/aleikin_artem_lab_3/TaskProject/obj
+/aleikin_artem_lab_4/RVIPLab4/.vs
+/aleikin_artem_lab_4/RVIPLab4/Consumer1/bin/Debug/net8.0
+/aleikin_artem_lab_4/RVIPLab4/Consumer1/obj
+/aleikin_artem_lab_4/RVIPLab4/Consumer2/bin/Debug/net8.0
+/aleikin_artem_lab_4/RVIPLab4/Consumer2/obj
+/aleikin_artem_lab_4/RVIPLab4/FirstTutorial/Receive/bin/Debug/net8.0
+/aleikin_artem_lab_4/RVIPLab4/FirstTutorial/Receive/obj
+/aleikin_artem_lab_4/RVIPLab4/FirstTutorial/Send/bin/Debug/net8.0
+/aleikin_artem_lab_4/RVIPLab4/FirstTutorial/Send/obj
+/aleikin_artem_lab_4/RVIPLab4/Publisher/bin/Debug/net8.0
+/aleikin_artem_lab_4/RVIPLab4/Publisher/obj
+/aleikin_artem_lab_4/RVIPLab4/SecondTutorial/NewTask/bin/Debug/net8.0
+/aleikin_artem_lab_4/RVIPLab4/SecondTutorial/NewTask/obj
+/aleikin_artem_lab_4/RVIPLab4/SecondTutorial/Worker/bin/Debug/net8.0
+/aleikin_artem_lab_4/RVIPLab4/SecondTutorial/Worker/obj
+/aleikin_artem_lab_4/RVIPLab4/ThirdTutorial/EmitLog/bin/Debug/net8.0
+/aleikin_artem_lab_4/RVIPLab4/ThirdTutorial/EmitLog/obj
+/aleikin_artem_lab_4/RVIPLab4/ThirdTutorial/ReceiveLogs/bin/Debug/net8.0
+/aleikin_artem_lab_4/RVIPLab4/ThirdTutorial/ReceiveLogs/obj
+/dozorova_alena_lab_2
+/dozorova_alena_lab_3
+/dozorova_alena_lab_4
+/dozorova_alena_lab_5/ConsoleApp1/obj
+/dozorova_alena_lab_6/ConsoleApp1/obj
+/aleikin_artem_lab_4/RVIPLab4/RVIPLab4.sln
+/aleikin_artem_lab_4/.vs
+/aleikin_artem_lab_4/Consumer1/bin/Debug/net8.0
+/aleikin_artem_lab_4/Consumer1/obj
+/aleikin_artem_lab_4/Consumer2/bin/Debug/net8.0
+/aleikin_artem_lab_4/Consumer2/obj
+/aleikin_artem_lab_4/FirstTutorial/Receive/bin/Debug/net8.0
+/aleikin_artem_lab_4/FirstTutorial/Receive/obj
+/aleikin_artem_lab_4/FirstTutorial/Send/bin/Debug/net8.0
+/aleikin_artem_lab_4/FirstTutorial/Send/obj
+/aleikin_artem_lab_4/Publisher/bin/Debug/net8.0
+/aleikin_artem_lab_4/Publisher/obj
+/aleikin_artem_lab_4/SecondTutorial/NewTask/bin/Debug/net8.0
+/aleikin_artem_lab_4/SecondTutorial/NewTask/obj
+/aleikin_artem_lab_4/SecondTutorial/Worker/bin/Debug/net8.0
+/aleikin_artem_lab_4/SecondTutorial/Worker/obj
+/aleikin_artem_lab_4/ThirdTutorial/EmitLog/bin/Debug/net8.0
+/aleikin_artem_lab_4/ThirdTutorial/EmitLog/obj
+/aleikin_artem_lab_4/ThirdTutorial/ReceiveLogs/bin/Debug/net8.0
+/aleikin_artem_lab_4/ThirdTutorial/ReceiveLogs/obj
+/aleikin_artem_lab_4/RVIPLab4.sln
diff --git a/aleikin_artem_lab_4/Consumer1/.dockerignore b/aleikin_artem_lab_4/Consumer1/.dockerignore
new file mode 100644
index 0000000..fe1152b
--- /dev/null
+++ b/aleikin_artem_lab_4/Consumer1/.dockerignore
@@ -0,0 +1,30 @@
+**/.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/**
\ No newline at end of file
diff --git a/aleikin_artem_lab_4/Consumer1/Consumer1.csproj b/aleikin_artem_lab_4/Consumer1/Consumer1.csproj
new file mode 100644
index 0000000..e5c330b
--- /dev/null
+++ b/aleikin_artem_lab_4/Consumer1/Consumer1.csproj
@@ -0,0 +1,17 @@
+
+
+
+ Exe
+ net8.0
+ enable
+ enable
+ Linux
+ .
+
+
+
+
+
+
+
+
diff --git a/aleikin_artem_lab_4/Consumer1/Consumer1.csproj.user b/aleikin_artem_lab_4/Consumer1/Consumer1.csproj.user
new file mode 100644
index 0000000..dd2d54c
--- /dev/null
+++ b/aleikin_artem_lab_4/Consumer1/Consumer1.csproj.user
@@ -0,0 +1,6 @@
+
+
+
+ Container (Dockerfile)
+
+
\ No newline at end of file
diff --git a/aleikin_artem_lab_4/Consumer1/Dockerfile b/aleikin_artem_lab_4/Consumer1/Dockerfile
new file mode 100644
index 0000000..bb67736
--- /dev/null
+++ b/aleikin_artem_lab_4/Consumer1/Dockerfile
@@ -0,0 +1,28 @@
+# См. статью по ссылке https://aka.ms/customizecontainer, чтобы узнать как настроить контейнер отладки и как Visual Studio использует этот Dockerfile для создания образов для ускорения отладки.
+
+# Этот этап используется при запуске из VS в быстром режиме (по умолчанию для конфигурации отладки)
+FROM mcr.microsoft.com/dotnet/runtime:8.0 AS base
+USER app
+WORKDIR /app
+
+
+# Этот этап используется для сборки проекта службы
+FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
+ARG BUILD_CONFIGURATION=Release
+WORKDIR /src
+COPY ["Consumer1.csproj", "."]
+RUN dotnet restore "./Consumer1.csproj"
+COPY . .
+WORKDIR "/src/."
+RUN dotnet build "./Consumer1.csproj" -c $BUILD_CONFIGURATION -o /app/build
+
+# Этот этап используется для публикации проекта службы, который будет скопирован на последний этап
+FROM build AS publish
+ARG BUILD_CONFIGURATION=Release
+RUN dotnet publish "./Consumer1.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
+
+# Этот этап используется в рабочей среде или при запуске из VS в обычном режиме (по умолчанию, когда конфигурация отладки не используется)
+FROM base AS final
+WORKDIR /app
+COPY --from=publish /app/publish .
+ENTRYPOINT ["dotnet", "Consumer1.dll"]
\ No newline at end of file
diff --git a/aleikin_artem_lab_4/Consumer1/Program.cs b/aleikin_artem_lab_4/Consumer1/Program.cs
new file mode 100644
index 0000000..6d7412e
--- /dev/null
+++ b/aleikin_artem_lab_4/Consumer1/Program.cs
@@ -0,0 +1,39 @@
+using RabbitMQ.Client;
+using RabbitMQ.Client.Events;
+using System.Text;
+
+var factory = new ConnectionFactory
+{
+ HostName = "rabbitmq",
+ UserName = "admin",
+ Password = "admin"
+};
+using var connection = await factory.CreateConnectionAsync();
+using var channel = await connection.CreateChannelAsync();
+
+var queueName = "slow_queue";
+var exchangeName = "logs_exchange";
+await channel.QueueDeclareAsync(queue: queueName, durable: true, exclusive: false, autoDelete: false, arguments: null);
+
+await channel.QueueBindAsync(queue: queueName, exchange: exchangeName, routingKey: "");
+
+Console.WriteLine("[Consumer1] Waiting for messages...");
+
+while (true)
+{
+ var consumer = new AsyncEventingBasicConsumer(channel);
+ consumer.ReceivedAsync += (model, ea) =>
+ {
+ var body = ea.Body.ToArray();
+ var message = Encoding.UTF8.GetString(body);
+ Console.WriteLine($"[Consumer1] Received: {message}");
+
+ Thread.Sleep(new Random().Next(2000, 3000));
+
+ Console.WriteLine("[Consumer1] Done processing");
+ channel.BasicAckAsync(deliveryTag: ea.DeliveryTag, multiple: false);
+ return Task.CompletedTask;
+ };
+
+ await channel.BasicConsumeAsync(queue: queueName, autoAck: false, consumer: consumer);
+}
\ No newline at end of file
diff --git a/aleikin_artem_lab_4/Consumer1/Properties/launchSettings.json b/aleikin_artem_lab_4/Consumer1/Properties/launchSettings.json
new file mode 100644
index 0000000..af5ad58
--- /dev/null
+++ b/aleikin_artem_lab_4/Consumer1/Properties/launchSettings.json
@@ -0,0 +1,10 @@
+{
+ "profiles": {
+ "Consumer1": {
+ "commandName": "Project"
+ },
+ "Container (Dockerfile)": {
+ "commandName": "Docker"
+ }
+ }
+}
\ No newline at end of file
diff --git a/aleikin_artem_lab_4/Consumer2/.dockerignore b/aleikin_artem_lab_4/Consumer2/.dockerignore
new file mode 100644
index 0000000..fe1152b
--- /dev/null
+++ b/aleikin_artem_lab_4/Consumer2/.dockerignore
@@ -0,0 +1,30 @@
+**/.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/**
\ No newline at end of file
diff --git a/aleikin_artem_lab_4/Consumer2/Consumer2.csproj b/aleikin_artem_lab_4/Consumer2/Consumer2.csproj
new file mode 100644
index 0000000..e5c330b
--- /dev/null
+++ b/aleikin_artem_lab_4/Consumer2/Consumer2.csproj
@@ -0,0 +1,17 @@
+
+
+
+ Exe
+ net8.0
+ enable
+ enable
+ Linux
+ .
+
+
+
+
+
+
+
+
diff --git a/aleikin_artem_lab_4/Consumer2/Consumer2.csproj.user b/aleikin_artem_lab_4/Consumer2/Consumer2.csproj.user
new file mode 100644
index 0000000..dd2d54c
--- /dev/null
+++ b/aleikin_artem_lab_4/Consumer2/Consumer2.csproj.user
@@ -0,0 +1,6 @@
+
+
+
+ Container (Dockerfile)
+
+
\ No newline at end of file
diff --git a/aleikin_artem_lab_4/Consumer2/Dockerfile b/aleikin_artem_lab_4/Consumer2/Dockerfile
new file mode 100644
index 0000000..e907f66
--- /dev/null
+++ b/aleikin_artem_lab_4/Consumer2/Dockerfile
@@ -0,0 +1,28 @@
+# См. статью по ссылке https://aka.ms/customizecontainer, чтобы узнать как настроить контейнер отладки и как Visual Studio использует этот Dockerfile для создания образов для ускорения отладки.
+
+# Этот этап используется при запуске из VS в быстром режиме (по умолчанию для конфигурации отладки)
+FROM mcr.microsoft.com/dotnet/runtime:8.0 AS base
+USER app
+WORKDIR /app
+
+
+# Этот этап используется для сборки проекта службы
+FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
+ARG BUILD_CONFIGURATION=Release
+WORKDIR /src
+COPY ["Consumer2.csproj", "."]
+RUN dotnet restore "./Consumer2.csproj"
+COPY . .
+WORKDIR "/src/."
+RUN dotnet build "./Consumer2.csproj" -c $BUILD_CONFIGURATION -o /app/build
+
+# Этот этап используется для публикации проекта службы, который будет скопирован на последний этап
+FROM build AS publish
+ARG BUILD_CONFIGURATION=Release
+RUN dotnet publish "./Consumer2.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
+
+# Этот этап используется в рабочей среде или при запуске из VS в обычном режиме (по умолчанию, когда конфигурация отладки не используется)
+FROM base AS final
+WORKDIR /app
+COPY --from=publish /app/publish .
+ENTRYPOINT ["dotnet", "Consumer2.dll"]
\ No newline at end of file
diff --git a/aleikin_artem_lab_4/Consumer2/Program.cs b/aleikin_artem_lab_4/Consumer2/Program.cs
new file mode 100644
index 0000000..2359d5b
--- /dev/null
+++ b/aleikin_artem_lab_4/Consumer2/Program.cs
@@ -0,0 +1,40 @@
+using RabbitMQ.Client;
+using RabbitMQ.Client.Events;
+using System.Data.Common;
+using System.Text;
+using System.Threading.Channels;
+
+var factory = new ConnectionFactory
+{
+ HostName = "rabbitmq",
+ UserName = "admin",
+ Password = "admin"
+};
+using var connection = await factory.CreateConnectionAsync();
+using var channel = await connection.CreateChannelAsync();
+
+var queueName = "fast_queue";
+var exchangeName = "logs_exchange";
+await channel.QueueDeclareAsync(queue: queueName, durable: true, exclusive: false, autoDelete: false, arguments: null);
+
+await channel.QueueBindAsync(queue: queueName, exchange: exchangeName, routingKey: "");
+
+Console.WriteLine("[Consumer2] Waiting for messages...");
+
+while (true)
+{
+ var consumer = new AsyncEventingBasicConsumer(channel);
+ consumer.ReceivedAsync += (model, ea) =>
+ {
+ var body = ea.Body.ToArray();
+ var message = Encoding.UTF8.GetString(body);
+ Console.WriteLine($"[Consumer2] Received: {message}");
+
+ Console.WriteLine("[Consumer2] Done processing");
+ channel.BasicAckAsync(deliveryTag: ea.DeliveryTag, multiple: false);
+ return Task.CompletedTask;
+ };
+
+ await channel.BasicConsumeAsync(queue: queueName, autoAck: false, consumer: consumer);
+ }
+
diff --git a/aleikin_artem_lab_4/Consumer2/Properties/launchSettings.json b/aleikin_artem_lab_4/Consumer2/Properties/launchSettings.json
new file mode 100644
index 0000000..a6b66b7
--- /dev/null
+++ b/aleikin_artem_lab_4/Consumer2/Properties/launchSettings.json
@@ -0,0 +1,10 @@
+{
+ "profiles": {
+ "Consumer2": {
+ "commandName": "Project"
+ },
+ "Container (Dockerfile)": {
+ "commandName": "Docker"
+ }
+ }
+}
\ No newline at end of file
diff --git a/aleikin_artem_lab_4/FirstTutorial/Receive/Receive.cs b/aleikin_artem_lab_4/FirstTutorial/Receive/Receive.cs
new file mode 100644
index 0000000..4aa46d9
--- /dev/null
+++ b/aleikin_artem_lab_4/FirstTutorial/Receive/Receive.cs
@@ -0,0 +1,26 @@
+using RabbitMQ.Client;
+using RabbitMQ.Client.Events;
+using System.Text;
+
+var factory = new ConnectionFactory { HostName = "localhost" };
+using var connection = await factory.CreateConnectionAsync();
+using var channel = await connection.CreateChannelAsync();
+
+await channel.QueueDeclareAsync(queue: "hello", durable: false,
+ exclusive: false, autoDelete: false,arguments: null);
+
+Console.WriteLine("[*] Waiting for messages...");
+
+var consumer = new AsyncEventingBasicConsumer(channel);
+consumer.ReceivedAsync += (model, ea) =>
+{
+ var body = ea.Body.ToArray();
+ var message = Encoding.UTF8.GetString(body);
+ Console.WriteLine($" [*] Received {message}");
+ return Task.CompletedTask;
+};
+
+await channel.BasicConsumeAsync("hello", autoAck: true, consumer: consumer);
+
+Console.WriteLine(" Press [enter] to exit.");
+Console.ReadLine();
\ No newline at end of file
diff --git a/aleikin_artem_lab_4/FirstTutorial/Receive/Receive.csproj b/aleikin_artem_lab_4/FirstTutorial/Receive/Receive.csproj
new file mode 100644
index 0000000..c6d2a4d
--- /dev/null
+++ b/aleikin_artem_lab_4/FirstTutorial/Receive/Receive.csproj
@@ -0,0 +1,14 @@
+
+
+
+ Exe
+ net8.0
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/aleikin_artem_lab_4/FirstTutorial/Send/Send.cs b/aleikin_artem_lab_4/FirstTutorial/Send/Send.cs
new file mode 100644
index 0000000..c315662
--- /dev/null
+++ b/aleikin_artem_lab_4/FirstTutorial/Send/Send.cs
@@ -0,0 +1,18 @@
+using RabbitMQ.Client;
+using System.Text;
+
+var factory = new ConnectionFactory { HostName = "localhost" };
+using var connection = await factory.CreateConnectionAsync();
+using var channel = await connection.CreateChannelAsync();
+
+await channel.QueueDeclareAsync(queue: "hello", durable: false,
+ exclusive: false, autoDelete: false, arguments: null);
+
+const string message = "Hello, World! ~from Artem";
+var body = Encoding.UTF8.GetBytes(message);
+
+await channel.BasicPublishAsync(exchange: string.Empty, routingKey: "hello", body: body);
+Console.WriteLine($" [x] Sent {message}");
+
+Console.WriteLine(" Press [enter] to exit.");
+Console.ReadLine();
\ No newline at end of file
diff --git a/aleikin_artem_lab_4/FirstTutorial/Send/Send.csproj b/aleikin_artem_lab_4/FirstTutorial/Send/Send.csproj
new file mode 100644
index 0000000..c6d2a4d
--- /dev/null
+++ b/aleikin_artem_lab_4/FirstTutorial/Send/Send.csproj
@@ -0,0 +1,14 @@
+
+
+
+ Exe
+ net8.0
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/aleikin_artem_lab_4/Images/Лаба_Отчет1.png b/aleikin_artem_lab_4/Images/Лаба_Отчет1.png
new file mode 100644
index 0000000..159ff09
Binary files /dev/null and b/aleikin_artem_lab_4/Images/Лаба_Отчет1.png differ
diff --git a/aleikin_artem_lab_4/Images/Лаба_Отчет2.png b/aleikin_artem_lab_4/Images/Лаба_Отчет2.png
new file mode 100644
index 0000000..047f25f
Binary files /dev/null and b/aleikin_artem_lab_4/Images/Лаба_Отчет2.png differ
diff --git a/aleikin_artem_lab_4/Images/Лаба_Отчет3.png b/aleikin_artem_lab_4/Images/Лаба_Отчет3.png
new file mode 100644
index 0000000..e306085
Binary files /dev/null and b/aleikin_artem_lab_4/Images/Лаба_Отчет3.png differ
diff --git a/aleikin_artem_lab_4/Images/Лаба_Отчет4.png b/aleikin_artem_lab_4/Images/Лаба_Отчет4.png
new file mode 100644
index 0000000..91bc4e7
Binary files /dev/null and b/aleikin_artem_lab_4/Images/Лаба_Отчет4.png differ
diff --git a/aleikin_artem_lab_4/Images/Туториал_1.png b/aleikin_artem_lab_4/Images/Туториал_1.png
new file mode 100644
index 0000000..a5213b7
Binary files /dev/null and b/aleikin_artem_lab_4/Images/Туториал_1.png differ
diff --git a/aleikin_artem_lab_4/Images/Туториал_2.png b/aleikin_artem_lab_4/Images/Туториал_2.png
new file mode 100644
index 0000000..d33f7bc
Binary files /dev/null and b/aleikin_artem_lab_4/Images/Туториал_2.png differ
diff --git a/aleikin_artem_lab_4/Images/Туториал_3.png b/aleikin_artem_lab_4/Images/Туториал_3.png
new file mode 100644
index 0000000..58b057e
Binary files /dev/null and b/aleikin_artem_lab_4/Images/Туториал_3.png differ
diff --git a/aleikin_artem_lab_4/Publisher/.dockerignore b/aleikin_artem_lab_4/Publisher/.dockerignore
new file mode 100644
index 0000000..fe1152b
--- /dev/null
+++ b/aleikin_artem_lab_4/Publisher/.dockerignore
@@ -0,0 +1,30 @@
+**/.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/**
\ No newline at end of file
diff --git a/aleikin_artem_lab_4/Publisher/Dockerfile b/aleikin_artem_lab_4/Publisher/Dockerfile
new file mode 100644
index 0000000..3d6e901
--- /dev/null
+++ b/aleikin_artem_lab_4/Publisher/Dockerfile
@@ -0,0 +1,28 @@
+# См. статью по ссылке https://aka.ms/customizecontainer, чтобы узнать как настроить контейнер отладки и как Visual Studio использует этот Dockerfile для создания образов для ускорения отладки.
+
+# Этот этап используется при запуске из VS в быстром режиме (по умолчанию для конфигурации отладки)
+FROM mcr.microsoft.com/dotnet/runtime:8.0 AS base
+USER app
+WORKDIR /app
+
+
+# Этот этап используется для сборки проекта службы
+FROM mcr.microsoft.com/dotnet/sdk:8.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
+
+# Этот этап используется в рабочей среде или при запуске из VS в обычном режиме (по умолчанию, когда конфигурация отладки не используется)
+FROM base AS final
+WORKDIR /app
+COPY --from=publish /app/publish .
+ENTRYPOINT ["dotnet", "Publisher.dll"]
\ No newline at end of file
diff --git a/aleikin_artem_lab_4/Publisher/Properties/launchSettings.json b/aleikin_artem_lab_4/Publisher/Properties/launchSettings.json
new file mode 100644
index 0000000..c756d2e
--- /dev/null
+++ b/aleikin_artem_lab_4/Publisher/Properties/launchSettings.json
@@ -0,0 +1,10 @@
+{
+ "profiles": {
+ "Publisher": {
+ "commandName": "Project"
+ },
+ "Container (Dockerfile)": {
+ "commandName": "Docker"
+ }
+ }
+}
\ No newline at end of file
diff --git a/aleikin_artem_lab_4/Publisher/Publisher.cs b/aleikin_artem_lab_4/Publisher/Publisher.cs
new file mode 100644
index 0000000..2fc2932
--- /dev/null
+++ b/aleikin_artem_lab_4/Publisher/Publisher.cs
@@ -0,0 +1,31 @@
+using RabbitMQ.Client;
+using System.Text;
+
+var factory = new ConnectionFactory
+{
+ HostName = "rabbitmq",
+ UserName = "admin",
+ Password = "admin"
+};
+using var connection = await factory.CreateConnectionAsync();
+Console.WriteLine("Connection established.");
+using var channel = await connection.CreateChannelAsync();
+Console.WriteLine("Channel created.");
+
+await channel.ExchangeDeclareAsync(exchange: "logs_exchange", type: ExchangeType.Fanout);
+
+while (true)
+{
+ var message = $"Event: {GenerateRandomEvent()}";
+ var body = Encoding.UTF8.GetBytes(message);
+
+ await channel.BasicPublishAsync(exchange: "logs_exchange", routingKey: string.Empty, body: body);
+ Console.WriteLine($"[Publisher] Sent: {message}");
+ await Task.Delay(1000);
+}
+
+static string GenerateRandomEvent()
+{
+ var events = new[] { "Order Received", "User Message", "Create Report" };
+ return events[new Random().Next(events.Length)] + " #" + new Random().Next(0, 99);
+}
diff --git a/aleikin_artem_lab_4/Publisher/Publisher.csproj b/aleikin_artem_lab_4/Publisher/Publisher.csproj
new file mode 100644
index 0000000..e5c330b
--- /dev/null
+++ b/aleikin_artem_lab_4/Publisher/Publisher.csproj
@@ -0,0 +1,17 @@
+
+
+
+ Exe
+ net8.0
+ enable
+ enable
+ Linux
+ .
+
+
+
+
+
+
+
+
diff --git a/aleikin_artem_lab_4/Publisher/Publisher.csproj.user b/aleikin_artem_lab_4/Publisher/Publisher.csproj.user
new file mode 100644
index 0000000..dd2d54c
--- /dev/null
+++ b/aleikin_artem_lab_4/Publisher/Publisher.csproj.user
@@ -0,0 +1,6 @@
+
+
+
+ Container (Dockerfile)
+
+
\ No newline at end of file
diff --git a/aleikin_artem_lab_4/SecondTutorial/NewTask/NewTask.csproj b/aleikin_artem_lab_4/SecondTutorial/NewTask/NewTask.csproj
new file mode 100644
index 0000000..c6d2a4d
--- /dev/null
+++ b/aleikin_artem_lab_4/SecondTutorial/NewTask/NewTask.csproj
@@ -0,0 +1,14 @@
+
+
+
+ Exe
+ net8.0
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/aleikin_artem_lab_4/SecondTutorial/NewTask/Program.cs b/aleikin_artem_lab_4/SecondTutorial/NewTask/Program.cs
new file mode 100644
index 0000000..4cf8ce8
--- /dev/null
+++ b/aleikin_artem_lab_4/SecondTutorial/NewTask/Program.cs
@@ -0,0 +1,26 @@
+using RabbitMQ.Client;
+using System.Text;
+
+var factory = new ConnectionFactory { HostName = "localhost" };
+using var connection = await factory.CreateConnectionAsync();
+using var channel = await connection.CreateChannelAsync();
+
+await channel.QueueDeclareAsync(queue: "task_queue", durable: true, exclusive: false,
+ autoDelete: false, arguments: null);
+
+var message = GetMessage(args);
+var body = Encoding.UTF8.GetBytes(message);
+
+var properties = new BasicProperties
+{
+ Persistent = true
+};
+
+await channel.BasicPublishAsync(exchange: string.Empty, routingKey: "task_queue", mandatory: true,
+ basicProperties: properties, body: body);
+Console.WriteLine($" [x] Sent {message}");
+
+static string GetMessage(string[] args)
+{
+ return ((args.Length > 0) ? string.Join(" ", args) : "Hello World!");
+}
\ No newline at end of file
diff --git a/aleikin_artem_lab_4/SecondTutorial/Worker/Program.cs b/aleikin_artem_lab_4/SecondTutorial/Worker/Program.cs
new file mode 100644
index 0000000..ccd6c27
--- /dev/null
+++ b/aleikin_artem_lab_4/SecondTutorial/Worker/Program.cs
@@ -0,0 +1,35 @@
+using RabbitMQ.Client;
+using RabbitMQ.Client.Events;
+using System.Text;
+
+var factory = new ConnectionFactory { HostName = "localhost" };
+using var connection = await factory.CreateConnectionAsync();
+using var channel = await connection.CreateChannelAsync();
+
+await channel.QueueDeclareAsync(queue: "task_queue", durable: true, exclusive: false,
+ autoDelete: false, arguments: null);
+
+await channel.BasicQosAsync(prefetchSize: 0, prefetchCount: 1, global: false);
+
+Console.WriteLine(" [*] Waiting for messages.");
+
+var consumer = new AsyncEventingBasicConsumer(channel);
+consumer.ReceivedAsync += async (model, ea) =>
+{
+ byte[] body = ea.Body.ToArray();
+ var message = Encoding.UTF8.GetString(body);
+ Console.WriteLine($" [x] Received {message}");
+
+ int dots = message.Split('.').Length - 1;
+ await Task.Delay(dots * 1000);
+
+ Console.WriteLine(" [x] Done");
+
+ // here channel could also be accessed as ((AsyncEventingBasicConsumer)sender).Channel
+ await channel.BasicAckAsync(deliveryTag: ea.DeliveryTag, multiple: false);
+};
+
+await channel.BasicConsumeAsync("task_queue", autoAck: false, consumer: consumer);
+
+Console.WriteLine(" Press [enter] to exit.");
+Console.ReadLine();
\ No newline at end of file
diff --git a/aleikin_artem_lab_4/SecondTutorial/Worker/Worker.csproj b/aleikin_artem_lab_4/SecondTutorial/Worker/Worker.csproj
new file mode 100644
index 0000000..c6d2a4d
--- /dev/null
+++ b/aleikin_artem_lab_4/SecondTutorial/Worker/Worker.csproj
@@ -0,0 +1,14 @@
+
+
+
+ Exe
+ net8.0
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/aleikin_artem_lab_4/ThirdTutorial/EmitLog/EmitLog.cs b/aleikin_artem_lab_4/ThirdTutorial/EmitLog/EmitLog.cs
new file mode 100644
index 0000000..9d3bdcf
--- /dev/null
+++ b/aleikin_artem_lab_4/ThirdTutorial/EmitLog/EmitLog.cs
@@ -0,0 +1,21 @@
+using RabbitMQ.Client;
+using System.Text;
+
+var factory = new ConnectionFactory { HostName = "localhost" };
+using var connection = await factory.CreateConnectionAsync();
+using var channel = await connection.CreateChannelAsync();
+
+await channel.ExchangeDeclareAsync(exchange: "logs", type: ExchangeType.Fanout);
+
+var message = GetMessage(args);
+var body = Encoding.UTF8.GetBytes(message);
+await channel.BasicPublishAsync(exchange: "logs", routingKey: string.Empty, 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!");
+}
\ No newline at end of file
diff --git a/aleikin_artem_lab_4/ThirdTutorial/EmitLog/EmitLog.csproj b/aleikin_artem_lab_4/ThirdTutorial/EmitLog/EmitLog.csproj
new file mode 100644
index 0000000..c6d2a4d
--- /dev/null
+++ b/aleikin_artem_lab_4/ThirdTutorial/EmitLog/EmitLog.csproj
@@ -0,0 +1,14 @@
+
+
+
+ Exe
+ net8.0
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/aleikin_artem_lab_4/ThirdTutorial/ReceiveLogs/ReceiveLogs.cs b/aleikin_artem_lab_4/ThirdTutorial/ReceiveLogs/ReceiveLogs.cs
new file mode 100644
index 0000000..e02e396
--- /dev/null
+++ b/aleikin_artem_lab_4/ThirdTutorial/ReceiveLogs/ReceiveLogs.cs
@@ -0,0 +1,31 @@
+using RabbitMQ.Client;
+using RabbitMQ.Client.Events;
+using System.Text;
+
+var factory = new ConnectionFactory { HostName = "localhost" };
+using var connection = await factory.CreateConnectionAsync();
+using var channel = await connection.CreateChannelAsync();
+
+await channel.ExchangeDeclareAsync(exchange: "logs",
+ type: ExchangeType.Fanout);
+
+// declare a server-named queue
+QueueDeclareOk queueDeclareResult = await channel.QueueDeclareAsync();
+string queueName = queueDeclareResult.QueueName;
+await channel.QueueBindAsync(queue: queueName, exchange: "logs", routingKey: string.Empty);
+
+Console.WriteLine(" [*] Waiting for logs.");
+
+var consumer = new AsyncEventingBasicConsumer(channel);
+consumer.ReceivedAsync += (model, ea) =>
+{
+ byte[] body = ea.Body.ToArray();
+ var message = Encoding.UTF8.GetString(body);
+ Console.WriteLine($" [x] {message}");
+ return Task.CompletedTask;
+};
+
+await channel.BasicConsumeAsync(queueName, autoAck: true, consumer: consumer);
+
+Console.WriteLine(" Press [enter] to exit.");
+Console.ReadLine();
\ No newline at end of file
diff --git a/aleikin_artem_lab_4/ThirdTutorial/ReceiveLogs/ReceiveLogs.csproj b/aleikin_artem_lab_4/ThirdTutorial/ReceiveLogs/ReceiveLogs.csproj
new file mode 100644
index 0000000..c6d2a4d
--- /dev/null
+++ b/aleikin_artem_lab_4/ThirdTutorial/ReceiveLogs/ReceiveLogs.csproj
@@ -0,0 +1,14 @@
+
+
+
+ Exe
+ net8.0
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/aleikin_artem_lab_4/docker-compose.yml b/aleikin_artem_lab_4/docker-compose.yml
new file mode 100644
index 0000000..52bd85f
--- /dev/null
+++ b/aleikin_artem_lab_4/docker-compose.yml
@@ -0,0 +1,61 @@
+services:
+ rabbitmq:
+ image: rabbitmq:management
+ container_name: rabbitmq
+ restart: always
+ ports:
+ - "5672:5672"
+ - "15672:15672"
+ environment:
+ RABBITMQ_DEFAULT_USER: admin
+ RABBITMQ_DEFAULT_PASS: admin
+ networks:
+ - my_network
+
+ publisher:
+ build:
+ context: ./Publisher
+ restart: always
+ depends_on:
+ - rabbitmq
+ environment:
+ RABBITMQ_HOST: rabbitmq
+ RABBIT_USERNAME: admin
+ RABBIT_PASSWORD: admin
+ RABBIT_EXCHANGE: 'logs_exchange'
+ networks:
+ - my_network
+
+ consumer1:
+ build:
+ context: ./Consumer1
+ restart: always
+ depends_on:
+ - rabbitmq
+ environment:
+ RABBITMQ_HOST: rabbitmq
+ RABBIT_USERNAME: admin
+ RABBIT_PASSWORD: admin
+ RABBIT_EXCHANGE: 'logs_exchange'
+ RABBIT_QUEUE: 'slow_queue'
+ networks:
+ - my_network
+
+ consumer2:
+ build:
+ context: ./Consumer2
+ restart: always
+ depends_on:
+ - rabbitmq
+ environment:
+ RABBITMQ_HOST: rabbitmq
+ RABBIT_USERNAME: admin
+ RABBIT_PASSWORD: admin
+ RABBIT_EXCHANGE: 'logs_exchange'
+ RABBIT_QUEUE: 'fast_queue'
+ networks:
+ - my_network
+
+networks:
+ my_network:
+ driver: bridge
\ No newline at end of file
diff --git a/aleikin_artem_lab_4/readme.md b/aleikin_artem_lab_4/readme.md
new file mode 100644
index 0000000..5174591
--- /dev/null
+++ b/aleikin_artem_lab_4/readme.md
@@ -0,0 +1,37 @@
+# Лабораторная работа 4 - Работа с брокером сообщений
+## ПИбд-42 || Алейкин Артем
+
+### Описание
+В данной лабораторной работе мы познакомились с такой утилитой как RabbitMQ.
+
+### Туториалы
+1. HelloWorld - Tutorial
+![Консольный вывод - первый туториал](./Images/Туториал_1.png)
+
+2. Work Queues - Tutorial
+![Консольный вывод - второй туториал](./Images/Туториал_2.png)
+
+3. Publish/Subscribe - Tutorial
+![Консольный вывод - третий туториал](./Images/Туториал_3.png)
+
+### Основное задание
+Было разработано 3 приложения: Publisher, Consumer1 и Consumer2.
+Первое отвечало за доставку сообщений в очереди. Оно генерирует одно сообщение раз в секунду.
+Второе и Третье за обработку этих сообщений из очередей, но Consumer1 имел искусственную задержку в 2-3 секунды, в то время как Consumer2 таких ограничений не имел и работу.
+
+### Шаги для запуска:
+1. Запуск контейнеров:
+```
+docker-compose up -d
+```
+
+В результате мы можем посмотреть графики по этой ссылке http://localhost:15672/
+![График Consumer1 - медленный](./Images/Лаба_Отчет2.png)
+![График Consumer2 - быстрый](./Images/Лаба_Отчет1.png)
+
+После этого было добавлено еще 3 клиента типа Consumer1 и только после этого их суммарной производительности стало хватать для обработки сообщений.
+![График Consumer1 для нескольких клиентов - медленный](./Images/Лаба_Отчет3.png)
+![График Consumer2 - быстрый](./Images/Лаба_Отчет4.png)
+
+
+Видео демонстрации работы: https://vk.com/video248424990_456239611?list=ln-v0VkWDOiRBxdctENzV
\ No newline at end of file