diff --git a/savenkov_alexander_lab_4/.idea/.gitignore b/savenkov_alexander_lab_4/.idea/.gitignore
new file mode 100644
index 0000000..26d3352
--- /dev/null
+++ b/savenkov_alexander_lab_4/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/savenkov_alexander_lab_4/.idea/discord.xml b/savenkov_alexander_lab_4/.idea/discord.xml
new file mode 100644
index 0000000..30bab2a
--- /dev/null
+++ b/savenkov_alexander_lab_4/.idea/discord.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/savenkov_alexander_lab_4/.idea/inspectionProfiles/profiles_settings.xml b/savenkov_alexander_lab_4/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..105ce2d
--- /dev/null
+++ b/savenkov_alexander_lab_4/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/savenkov_alexander_lab_4/.idea/misc.xml b/savenkov_alexander_lab_4/.idea/misc.xml
new file mode 100644
index 0000000..fe43ca6
--- /dev/null
+++ b/savenkov_alexander_lab_4/.idea/misc.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/savenkov_alexander_lab_4/.idea/modules.xml b/savenkov_alexander_lab_4/.idea/modules.xml
new file mode 100644
index 0000000..593b461
--- /dev/null
+++ b/savenkov_alexander_lab_4/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/savenkov_alexander_lab_4/.idea/savenkov_alexander_lab_4.iml b/savenkov_alexander_lab_4/.idea/savenkov_alexander_lab_4.iml
new file mode 100644
index 0000000..74d515a
--- /dev/null
+++ b/savenkov_alexander_lab_4/.idea/savenkov_alexander_lab_4.iml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/savenkov_alexander_lab_4/README.md b/savenkov_alexander_lab_4/README.md
new file mode 100644
index 0000000..874f710
--- /dev/null
+++ b/savenkov_alexander_lab_4/README.md
@@ -0,0 +1,69 @@
+# Лабораторная работа №4 - Работа с брокером сообщений
+
+Цель: изучение проектирования приложений при помощи брокера сообщений.
+
+Задачи:
+
+Необходимо выбрать предметную область и разработать следующие приложения:
+
+Publisher. Программа, которая создаёт один exchange с типом fanout. Программа должна раз в секунду генерировать сообщения в журнал событий согласно вашей предметной области. Например, событие "пришёл заказ" или "сообщение от пользователя" или "необходимо создать отчёт".
+Consumer 1. Программа, которая создаёт под себя отдельную не анонимную (!) очередь (queue) (то есть имя queue НЕ пустая строка), создаёт binding на exchange и начинает принимать сообщения (consume). Программа должна обрабатывать сообщения 2-3 секунды. Можно реализовать через обычный Thread.Sleep (для C#).
+Consumer 2. Аналогично Consumer 1, только сообщения необходимо обрабатывать моментально. Только имя очереди должно отличаться от Consumer 1.
+Далее необходимо собрать и запустить приложения одновременно по одному экземпляру.
+
+Сделать в отчёте вывод о скорости обработки consumer-ами событий от publisher-а. Для этого можно посмотреть заполненность созданных очередей. А для этого можно использовать скриншот из RabbitMQ Management UI.
+
+Запустить несколько копий Consumer 1. Проверить заново заполненность очередей через UI.
+
+# Publisher
+
+
Код Publisher
+
+
+
+
Работа Publisher
+
+
+
+# Consumer 1
+
+
+
Код Consumer 1
+
+
+
+
Работа Consumer 1
+
+
+
+# Consumer 2
+
+
+
+
+
+
+
Работа Consumer 2
+
+
+
+# RabbitMQ Management UI
+
+
+
До запусков Consumer
+
+
+
+
После запуска Consumer 1
+
+
+
+
После запуска Consumer 2
+
+
+
+Вывод: по данным об очередях с RabbitMQ Management UI видно, что второй Consumer работает быстрее и ограничен лишь скоростью отправки сообщений, но если скорость отправки сообщений не будет ограничена, то возникает риск пропуска сообщений, а также такой метод сильнее нагружает систему и усложняет отслеживания работоспособности системы, что может привести к сбоям.
+
+# Видео
+
+Видео с разбором лабораторной работы - https://youtu.be/8GOG8MyPkO4
diff --git a/savenkov_alexander_lab_4/inventory_consumer.py b/savenkov_alexander_lab_4/inventory_consumer.py
new file mode 100644
index 0000000..85d3958
--- /dev/null
+++ b/savenkov_alexander_lab_4/inventory_consumer.py
@@ -0,0 +1,34 @@
+import pika
+import time
+
+def process_inventory_event(ch, method, properties, body):
+ decoded_message = body.decode('utf-8')
+ print(f" [x] Processing Inventory Event: {decoded_message}")
+ time.sleep(2)
+ print(" [x] Done")
+ ch.basic_ack(delivery_tag=method.delivery_tag)
+
+def main():
+ # Устанавливаем соединение с сервером RabbitMQ
+ connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
+ channel = connection.channel()
+
+ # Объявляем exchange с типом 'fanout'
+ channel.exchange_declare(exchange='events', exchange_type='fanout')
+
+ # Создаем очередь с уникальным именем
+ result = channel.queue_declare(queue='', exclusive=True)
+ queue_name = result.method.queue
+
+ # Привязываем очередь к exchange
+ channel.queue_bind(exchange='events', queue=queue_name)
+
+ # Указываем, как обрабатывать сообщения при получении
+ channel.basic_consume(queue=queue_name, on_message_callback=process_inventory_event)
+
+ print(' [*] Waiting for Inventory Events. To exit press CTRL+C')
+ # Запускаем бесконечный цикл получения и обработки сообщений
+ channel.start_consuming()
+
+if __name__ == '__main__':
+ main()
diff --git a/savenkov_alexander_lab_4/order_processing_consumer.py b/savenkov_alexander_lab_4/order_processing_consumer.py
new file mode 100644
index 0000000..3e222ba
--- /dev/null
+++ b/savenkov_alexander_lab_4/order_processing_consumer.py
@@ -0,0 +1,34 @@
+import pika
+import time
+
+def process_order_event(ch, method, properties, body):
+ decoded_message = body.decode('utf-8')
+ print(f" [x] Processing Order Event: {decoded_message}")
+ # No delay for Consumer 2
+ print(" [x] Done")
+ ch.basic_ack(delivery_tag=method.delivery_tag)
+
+def main():
+ # Устанавливаем соединение с сервером RabbitMQ
+ connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
+ channel = connection.channel()
+
+ # Объявляем exchange с типом 'fanout'
+ channel.exchange_declare(exchange='events', exchange_type='fanout')
+
+ # Создаем очередь с уникальным именем
+ result = channel.queue_declare(queue='', exclusive=True)
+ queue_name = result.method.queue
+
+ # Привязываем очередь к exchange
+ channel.queue_bind(exchange='events', queue=queue_name)
+
+ # Указываем, как обрабатывать сообщения при получении
+ channel.basic_consume(queue=queue_name, on_message_callback=process_order_event)
+
+ print(' [*] Waiting for Order Events. To exit press CTRL+C')
+ # Запускаем бесконечный цикл получения и обработки сообщений
+ channel.start_consuming()
+
+if __name__ == '__main__':
+ main()
diff --git a/savenkov_alexander_lab_4/publisher.py b/savenkov_alexander_lab_4/publisher.py
new file mode 100644
index 0000000..a73d738
--- /dev/null
+++ b/savenkov_alexander_lab_4/publisher.py
@@ -0,0 +1,26 @@
+import pika
+import time
+import random
+
+def generate_order_event(channel):
+ order_id = random.randint(1, 1000)
+ event = f"Поступил новый заказ #{order_id}"
+ message = f"Событие: {event}"
+ channel.basic_publish(exchange='events', routing_key='', body=message)
+ print(f" [x] Sent: {message}")
+
+def main():
+ # Устанавливаем соединение с сервером RabbitMQ
+ connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
+ channel = connection.channel()
+
+ # Объявляем exchange с типом 'fanout'
+ channel.exchange_declare(exchange='events', exchange_type='fanout')
+
+ # В бесконечном цикле генерируем и отправляем события в RabbitMQ
+ while True:
+ generate_order_event(channel)
+ time.sleep(1)
+
+if __name__ == '__main__':
+ main()
diff --git a/savenkov_alexander_lab_4/screens/img1.png b/savenkov_alexander_lab_4/screens/img1.png
new file mode 100644
index 0000000..959c42d
Binary files /dev/null and b/savenkov_alexander_lab_4/screens/img1.png differ
diff --git a/savenkov_alexander_lab_4/screens/img2.png b/savenkov_alexander_lab_4/screens/img2.png
new file mode 100644
index 0000000..d59368f
Binary files /dev/null and b/savenkov_alexander_lab_4/screens/img2.png differ
diff --git a/savenkov_alexander_lab_4/screens/img3.png b/savenkov_alexander_lab_4/screens/img3.png
new file mode 100644
index 0000000..02e5bad
Binary files /dev/null and b/savenkov_alexander_lab_4/screens/img3.png differ
diff --git a/savenkov_alexander_lab_4/screens/img4.png b/savenkov_alexander_lab_4/screens/img4.png
new file mode 100644
index 0000000..e963b1f
Binary files /dev/null and b/savenkov_alexander_lab_4/screens/img4.png differ
diff --git a/savenkov_alexander_lab_4/screens/img5.png b/savenkov_alexander_lab_4/screens/img5.png
new file mode 100644
index 0000000..c27847f
Binary files /dev/null and b/savenkov_alexander_lab_4/screens/img5.png differ
diff --git a/savenkov_alexander_lab_4/screens/img6.png b/savenkov_alexander_lab_4/screens/img6.png
new file mode 100644
index 0000000..d6320de
Binary files /dev/null and b/savenkov_alexander_lab_4/screens/img6.png differ
diff --git a/savenkov_alexander_lab_4/screens/img7.png b/savenkov_alexander_lab_4/screens/img7.png
new file mode 100644
index 0000000..d6253ff
Binary files /dev/null and b/savenkov_alexander_lab_4/screens/img7.png differ
diff --git a/savenkov_alexander_lab_4/screens/img8.png b/savenkov_alexander_lab_4/screens/img8.png
new file mode 100644
index 0000000..60fbd5c
Binary files /dev/null and b/savenkov_alexander_lab_4/screens/img8.png differ
diff --git a/savenkov_alexander_lab_4/screens/img9.png b/savenkov_alexander_lab_4/screens/img9.png
new file mode 100644
index 0000000..ac4d40a
Binary files /dev/null and b/savenkov_alexander_lab_4/screens/img9.png differ