diff --git a/morozov_vladimir_lab_2/.gitignore b/morozov_vladimir_lab_2/.gitignore new file mode 100644 index 0000000..723ef36 --- /dev/null +++ b/morozov_vladimir_lab_2/.gitignore @@ -0,0 +1 @@ +.idea \ No newline at end of file diff --git a/morozov_vladimir_lab_2/docker-compose.yml b/morozov_vladimir_lab_2/docker-compose.yml new file mode 100644 index 0000000..fa24e50 --- /dev/null +++ b/morozov_vladimir_lab_2/docker-compose.yml @@ -0,0 +1,23 @@ +version: '3' +# Объявляем сервисы +services: + + worker_0: # сервис приложения для генерации данных + build: ./worker_0/ # путь к его докер файлу + volumes: # монтируем том + - data:/usr/src/myData + worker_1: # сервис 1го приложения + build: ./worker_1/ # путь к его докер файлу + volumes: # монтируем том + - data:/usr/src/myData + depends_on: # объявляем, что данный сервис запуститься только после запуска сервиса worker_0 + worker_0: + condition: service_completed_successfully + worker_2: # сервис 2го приложения + build: ./worker_2/ # путь к его докер файлу + volumes: # монтируем том + - data:/usr/src/myData + depends_on: + - worker_1 # объявляем, что данный сервис запуститься только после запуска сервиса worker_1 +volumes: # объявляем тома + data: \ No newline at end of file diff --git a/morozov_vladimir_lab_2/readme.md b/morozov_vladimir_lab_2/readme.md new file mode 100644 index 0000000..6ccbe2d --- /dev/null +++ b/morozov_vladimir_lab_2/readme.md @@ -0,0 +1,45 @@ +# Лабораторная работа №2 - разработка простейшего распределенного приложения + +## Разработанные приложения +- worker_0 - программа, которая создаст папки /var/data и сгенерирует в них изначальные данные +- worker_1 - 1я программа. Вариант 4: Формирует файл /var/result/data.txt так, что каждая строка файла - количество символов в именах файлов из каталога /var/data +- worker_2 - 2я программа. Вариант 2: Ищет наименьшее число из файла /var/data/data.txt и сохраняет его третью степень в /var/result/result.txt + +Все программы были разработаны на языке Python. + +## DockerFile +Для каждого приложения был создан отдельный dockerfile, который позволяет нам создавать свои образы, на основе которых будут созданы контейнеры. Все файлы лежат в папках программ, описание имеет только dockerfile для `worker_0`, так как по структуре все они одинаковы + +## DockerCompose +Для того, чтобы запустить все программы нам нужно создать `docker-compose.yml`, в котором определим как запускать наши сервисы. В отличие от 1й л/р в `docker-compose.yml` были добавлены команды `build`, которая позволяет нам указать путь до dockerfile нашего приложения, а также `depends_on`, которая позволяет установить порядок запусков сервисов. Более подробное описание `docker-compose.yml` находится в нем самом в качестве комментариев + +## Как запустить +Для того, чтобы запустить наше распределенное приложение нужно выполнить несколько шагов +1) Запустить докер приложение. Я использую doker desktop. +2) Открыть терминал +3) перейти в папку, в которой лежит `docker-compose.yml`. Сделать это можно с помощью команды `cd` +3) Запустить команду: +``` +docker-compose up --build +``` +После этого будут созданые контейнеры, которые построены на основе образов, указанных в `docker-compose.yml`. В терминале будут отабражено следующее: +```[+] Running 5/5 + ✔ Network morozov_vladimir_lab_2_default Created + ✔ Volume "morozov_vladimir_lab_2_data" Created + ✔ Container morozov_vladimir_lab_2-worker_0-1 Created + ✔ Container morozov_vladimir_lab_2-worker_1-1 Created + ✔ Container morozov_vladimir_lab_2-worker_2-1 Created +Attaching to worker_0-1, worker_1-1, worker_2-1 +worker_0-1 | Start generating data +worker_0-1 | Create dir and files +worker_0-1 exited with code 0 +worker_1-1 | Start first app +worker_1-1 | Create dir +worker_1-1 exited with code 0 +worker_2-1 | Start second app +worker_2-1 | 0 +worker_2-1 exited with code 0 +``` + +## Запись тестирования +Работа приложения представлена в [видео](https://disk.yandex.ru/i/0KAySyP5eaBg0g) \ No newline at end of file diff --git a/morozov_vladimir_lab_2/worker_0/app.py b/morozov_vladimir_lab_2/worker_0/app.py new file mode 100644 index 0000000..6d61a2c --- /dev/null +++ b/morozov_vladimir_lab_2/worker_0/app.py @@ -0,0 +1,55 @@ +import os.path +import random +import sys +# программа для создания первоначальных данных + +# кол-во создаваемых файлов +count_files = 10 +# буквы для создани случайных названий файлов +letters = "a b c d e f g h i j k l m n o p q r s t u v w x y z" + +# создание папки /var/data +def create_dir(path): + os.makedirs(f"{path}/var/data") + +# заполнение файлов случайным кол-вом строк, состоящих из случайных чисел +def create_strings(file): + count_strings = random.randint(5,10) + for i in range(0, count_strings): + for _ in range(0,10): + file.write(f"{random.randint(0, 100)} ") + if i != count_strings-1: + file.write('\n') + + +# Создание файлов с данными +def create_files(path): + arr = letters.split() + with open(f"{path}/var/data/data.txt", 'w') as f: + create_strings(f) + for i in range(1, count_files): + name = "" + for _ in range(0, random.randint(3, 10)): + name += arr[random.randint(0, len(arr)-1)] + with open(f"{path}/var/data/{name}{i}.txt",'w') as f: + create_strings(f) + +# проверка на наличие папок и файлов +def check_dir(path): + if os.path.exists(f"{path}/var/data"): + if os.path.isfile(f"{path}/var/data/data.txt") and len(os.listdir(f"{path}/var/data")) >= count_files: + print("Already create") + else: + print("Create files") + create_files(path) + else: + print("Create dir and files") + create_dir(path) + create_files(path) + + +if __name__ == '__main__' : + print("Start generating data") + path = sys.argv[1] + check_dir(path) + diff --git a/morozov_vladimir_lab_2/worker_0/dockerfile b/morozov_vladimir_lab_2/worker_0/dockerfile new file mode 100644 index 0000000..02184d7 --- /dev/null +++ b/morozov_vladimir_lab_2/worker_0/dockerfile @@ -0,0 +1,8 @@ +# объявляем базовый образ, на основе которого будет все построено +FROM "python:3.9-slim" +# назначаем основную рабочую директорию +WORKDIR /usr/src/app +# копируем содержимое текущей папке (скрипт питона) в контейнер, в основную рабочую папку +COPY . . +# при запуске образа выполняем команду запуска приложения +CMD [ "python", "./app.py", "/usr/src/myData"] \ No newline at end of file diff --git a/morozov_vladimir_lab_2/worker_1/app.py b/morozov_vladimir_lab_2/worker_1/app.py new file mode 100644 index 0000000..6f3eb45 --- /dev/null +++ b/morozov_vladimir_lab_2/worker_1/app.py @@ -0,0 +1,30 @@ +import os +import sys +# 1я программа. +# Вариант 4: Формирует файл /var/result/data.txt так, +# что каждая строка файла - количество символов в именах файлов из каталога /var/data + +# Создание папки +def create_dir(path): + os.makedirs(f"{path}/var/result") + +# Создание файла result и заполнение его +def create_file(path): + with open(f"{path}/var/result/data.txt", 'w') as f: + files = os.listdir(f"{path}/var/data") + for i, file in enumerate(files): + f.write(f"{file} - {len(file.replace('.txt', ''))}") + if i != len(files)-1: + f.write('\n') + +# Проверка на наличие файла result +def check(path): + if not os.path.exists(f"{path}/var/result"): + print("Create dir") + create_dir(path) + create_file(path) + +if __name__ == '__main__' : + print("Start first app") + path = sys.argv[1] + check(path) diff --git a/morozov_vladimir_lab_2/worker_1/dockerfile b/morozov_vladimir_lab_2/worker_1/dockerfile new file mode 100644 index 0000000..02d501c --- /dev/null +++ b/morozov_vladimir_lab_2/worker_1/dockerfile @@ -0,0 +1,4 @@ +FROM "python:3.9-slim" +WORKDIR /usr/src/app +COPY . . +CMD [ "python", "./app.py", "/usr/src/myData"] \ No newline at end of file diff --git a/morozov_vladimir_lab_2/worker_2/app.py b/morozov_vladimir_lab_2/worker_2/app.py new file mode 100644 index 0000000..159e63e --- /dev/null +++ b/morozov_vladimir_lab_2/worker_2/app.py @@ -0,0 +1,27 @@ +import sys +# 2я Программа +# Вариант 2: Ищет наименьшее число из файла /var/data/data.txt +# и сохраняет его третью степень в /var/result/result.txt + + +# Основной метод, в котором открываем файл data.txt, ищем в нем наименьшее число и записываем его степень в result +def work(path): + result = 0 + with open(f"{path}/var/data/data.txt", 'r') as f: + strings = f.readlines() + min = int(strings[0].replace('\n','').split()[0]) + for string in strings: + arr = string.replace('\n','').split() + for num in arr: + if int(num) <= min: + min = int(num) + result = int(min)**3 + with open(f"{path}/var/result/result.txt", 'w') as f: + f.write(f"{result}") + print(result) + + +if __name__ == '__main__' : + print("Start second app") + path = sys.argv[1] + work(path) diff --git a/morozov_vladimir_lab_2/worker_2/dockerfile b/morozov_vladimir_lab_2/worker_2/dockerfile new file mode 100644 index 0000000..02d501c --- /dev/null +++ b/morozov_vladimir_lab_2/worker_2/dockerfile @@ -0,0 +1,4 @@ +FROM "python:3.9-slim" +WORKDIR /usr/src/app +COPY . . +CMD [ "python", "./app.py", "/usr/src/myData"] \ No newline at end of file diff --git a/morozov_vladimir_lab_3/.gitignore b/morozov_vladimir_lab_3/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/morozov_vladimir_lab_3/docker-compose.yml b/morozov_vladimir_lab_3/docker-compose.yml new file mode 100644 index 0000000..1abc057 --- /dev/null +++ b/morozov_vladimir_lab_3/docker-compose.yml @@ -0,0 +1,18 @@ +version: '3' +# Объявляем сервисы +services: + artists_srv: # сервис приложения артистов + build: ./service_artists/ + + paints_srv: # сервис приложения картин + build: ./service_paints/ + + gateway: # сервис nginx + image: nginx:latest # назначаем его образ + ports: # пробрасываем порта + - 8080:8080 + volumes: # перекидываем конфигурационный файл + - ./nginx.conf:/etc/nginx/nginx.conf + depends_on: # ожидаем запуска предыдущих сервисов + - artists_srv + - paints_srv diff --git a/morozov_vladimir_lab_3/nginx.conf b/morozov_vladimir_lab_3/nginx.conf new file mode 100644 index 0000000..f9f9e23 --- /dev/null +++ b/morozov_vladimir_lab_3/nginx.conf @@ -0,0 +1,39 @@ +events { + worker_connections 1024; +} +http +{ + + server { + listen 8080; + listen [::]:8080; + server_name localhost; + + location /artists/ { + proxy_pass http://artists_srv:8001/artists/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + + location /artists/docs { + proxy_pass http://artists_srv:8001/docs; + proxy_set_header Host $host; + } + + location /paints/docs { + proxy_pass http://paints_srv:8002/docs; + proxy_set_header Host $host; + } + + location /paints/ { + proxy_pass http://paints_srv:8002/paints/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + + } +} \ No newline at end of file diff --git a/morozov_vladimir_lab_3/readme.md b/morozov_vladimir_lab_3/readme.md new file mode 100644 index 0000000..257aab1 --- /dev/null +++ b/morozov_vladimir_lab_3/readme.md @@ -0,0 +1,26 @@ +# Лабораторная работа №3 - REST API, Gateway и синхронный обмен между микросервисами + +## Разработанные приложения +В рамках л/р были разработаны 2 приложения: +1) Сервис для работы с сущностью художник(artist). Сущность имеет следующие поля: + 1) uid (номер) + 2) name (ФИО) + 3) year (год рождения) +2) Сервис для работы с сущностью картина(paint). Сущность имеет следующие поля: + 1) uid (номер) + 2) title (название) + 3) year (год создания) + 4) author (номер художника) +Один художник(один) может создать несколько картин(многие) +## Приготовления +Для обеспечения нужной работоспособности нашего приложения был использован веб-сервер Nginx, который можем использовать в роли прокси сервера. +Для этого нужно было развернуть его в отдельном контейнере и настроить его конфигурационный файл, в которым мы описывали прослушиваемые адреса и куда нужно перенаправлять. +Сервисы развернули в обычном порядке: написали код приложения, создали докер-файл, записали в докер-композе. +## Запуск +Для запуска приложения используем команду: +``` +docker-compose up --build +``` + +## Запись тестирования +Работа приложения представлена в [видео](https://disk.yandex.ru/i/8yuoSm0QSR9wGw) \ No newline at end of file diff --git a/morozov_vladimir_lab_3/service_artists/app.py b/morozov_vladimir_lab_3/service_artists/app.py new file mode 100644 index 0000000..94deccc --- /dev/null +++ b/morozov_vladimir_lab_3/service_artists/app.py @@ -0,0 +1,77 @@ +import sys +import uuid +import uvicorn + +from fastapi import FastAPI, Body +from fastapi.responses import JSONResponse +from fastapi.encoders import jsonable_encoder + +app = FastAPI(title="Artists service") +# Сервис для работы с художниками +# класс сущности художник +class artist: + def __init__(self, name, year, uid=""): + if len(uid) == 0: + self.uid = str(uuid.uuid4()) + else: + self.uid = uid + self.name = name + self.year = year + +# Первоначальные данные +artists = [ + artist("Vincent van Gogh","1853","d1c02854-76d8-4a35-be5c-076f091a67c0"), + artist("Claude Monet","1840","41e2dadc-1aa8-4f14-b1e8-7fc5664d1cdf"), + artist("Ilya Repin","1844", "591f8c2f-1937-44a1-b1f8-ff1f8b52cece")] +# Получение всех художников +@app.get("/artists/") +async def get_all(): + json_data = jsonable_encoder(artists) + return JSONResponse(json_data) +# Получение конкретного художника +@app.get("/artists/{uid}") +def get_uid(uid): + for art in artists: + if art.uid == uid: + json_data = jsonable_encoder(art) + return JSONResponse(json_data) + return JSONResponse(content={"message": "Resource Not Found"}, status_code=404) +# Создание нового художника +@app.post("/artists/") +def create(name = Body(embed=True), year = Body(embed=True)): + for art in artists: + if art.name.lower() == name.lower(): + return JSONResponse(content={"message": "Resource Not Found"}, status_code=404) + new_artist = artist(name,year) + artists.append(new_artist) + json_data = jsonable_encoder(new_artist) + return JSONResponse(json_data) +# Изменение данных о художники +@app.put("/artists/{uid}") +def update(uid, name = Body(embed=True), year = Body(embed=True)): + for art in artists: + if uid == art.uid: + art.name = name + art.year = year + json_data = jsonable_encoder(art) + return JSONResponse(json_data) + return JSONResponse(content={"message": "Resource Not Found"}, status_code=404) +# Удаление художника +@app.delete("/artists/{uid}") +def delete(uid): + ind = 0 + find = False + for art in artists: + if art.uid == uid: + find = True + break + ind += 1 + + if find: + artists.pop(ind) + return JSONResponse(content={"message": "Resource Deleted"}, status_code=200) + else: + return JSONResponse(content={"message": "Resource Not Found"}, status_code=404) + +if __name__ == '__main__' : + uvicorn.run("app:app",host="0.0.0.0", port=8001,) \ No newline at end of file diff --git a/morozov_vladimir_lab_3/service_artists/dockerfile b/morozov_vladimir_lab_3/service_artists/dockerfile new file mode 100644 index 0000000..3d28ad3 --- /dev/null +++ b/morozov_vladimir_lab_3/service_artists/dockerfile @@ -0,0 +1,10 @@ +# объявляем базовый образ, на основе которого будет все построено +FROM "python:3.9-slim" +# назначаем основную рабочую директорию +WORKDIR /usr/src/app +# копируем содержимое текущей папке (скрипт питона) в контейнер, в основную рабочую папку +COPY . . +# установка req +RUN pip install -r req.txt +# при запуске образа выполняем команду запуска приложения +CMD [ "python", "app.py"] \ No newline at end of file diff --git a/morozov_vladimir_lab_3/service_artists/req.txt b/morozov_vladimir_lab_3/service_artists/req.txt new file mode 100644 index 0000000..d89375d --- /dev/null +++ b/morozov_vladimir_lab_3/service_artists/req.txt @@ -0,0 +1,4 @@ +fastapi[all] +uuid +uvicorn +requests \ No newline at end of file diff --git a/morozov_vladimir_lab_3/service_paints/app.py b/morozov_vladimir_lab_3/service_paints/app.py new file mode 100644 index 0000000..d05fa9e --- /dev/null +++ b/morozov_vladimir_lab_3/service_paints/app.py @@ -0,0 +1,95 @@ +import sys +import uuid +import requests +import uvicorn + +from fastapi import FastAPI, Body +from fastapi.responses import JSONResponse +from fastapi.encoders import jsonable_encoder + +app = FastAPI(title="Paints service") +# Сервис для работы с картинами +# Класс картины +class paint: + def __init__(self, title,year,author): + self.uid = str(uuid.uuid4()) + self.title = title + self.year = year + self.author = author + +# Первоначальные данные +paints = [ + paint("Sunflowers","1887", "d1c02854-76d8-4a35-be5c-076f091a67c0"), + paint("Self-portrait with a severed ear and a tube","1889", "d1c02854-76d8-4a35-be5c-076f091a67c0"), + paint("Boatmen on the Volga","1873", "591f8c2f-1937-44a1-b1f8-ff1f8b52cece")] + +# Получение всех картин +@app.get("/paints/") +async def get_all(): + json_data = jsonable_encoder(paints) + return JSONResponse(json_data) +# Получение конкретной картины +@app.get("/paints/{uid}") +def get_uid(uid): + for art in paints: + if art.uid == uid: + response = requests.get(f"http://artists_srv:8001/artists/{art.author}") + author = response.json() + result = { + "uid":art.uid, + "title":art.title, + "year":art.year, + "authorUid":art.author, + "author":author + } + json_data = jsonable_encoder(result) + return JSONResponse(json_data) + return JSONResponse(content={"message": "Resource Not Found"}, status_code=404) +# Создание новой картины +@app.post("/paints/") +def create(title = Body(embed=True), year = Body(embed=True), author = Body(embed=True)): + for art in paints: + if art.title.lower() == title.lower(): + return JSONResponse(content={"message": "Resource Not Found"}, status_code=404) + response = requests.get(f"http://artists_srv:8001/artists/{author}") + if response.status_code == 404: + return JSONResponse(content={"message": "Resource Not Found"}, status_code=404) + new_paint = paint(title,year, author) + paints.append(new_paint) + json_data = jsonable_encoder(new_paint) + return JSONResponse(json_data) +# Обновление данных о картине +@app.put("/paints/{uid}") +def update(uid, title = Body(embed=True), year = Body(embed=True), author = Body(embed=True)): + response = requests.get(f"http://artists_srv:8001/artists/{author}") + print(author) + print(response.status_code) + if response.status_code == 404: + return JSONResponse(content={"message": "Resource Not Found"}, status_code=404) + for art in paints: + if uid == art.uid: + art.title = title + art.year = year + art.author = author + json_data = jsonable_encoder(art) + return JSONResponse(json_data) + return JSONResponse(content={"message": "Resource Not Found"}, status_code=404) +# Удаление картины +@app.delete("/paints/{uid}") +def delete(uid): + ind = 0 + find = False + for art in paints: + if art.uid == uid: + find = True + break + ind += 1 + + if find: + paints.pop(ind) + return JSONResponse(content={"message": "Resource Deleted"}, status_code=200) + else: + return JSONResponse(content={"message": "Resource Not Found"}, status_code=404) + +if __name__ == '__main__' : + uvicorn.run("app:app", host="0.0.0.0", port=8002,) \ No newline at end of file diff --git a/morozov_vladimir_lab_3/service_paints/dockerfile b/morozov_vladimir_lab_3/service_paints/dockerfile new file mode 100644 index 0000000..4ee7001 --- /dev/null +++ b/morozov_vladimir_lab_3/service_paints/dockerfile @@ -0,0 +1,10 @@ +# объявляем базовый образ, на основе которого будет все построено +FROM "python:3.9-slim" +# назначаем основную рабочую директорию +WORKDIR /usr/src/app +# копируем содержимое текущей папке (скрипт питона) в контейнер, в основную рабочую папку +COPY . . +# установка зависимостей +RUN pip install -r req.txt +# при запуске образа выполняем команду запуска приложения +CMD [ "python", "app.py"] \ No newline at end of file diff --git a/morozov_vladimir_lab_3/service_paints/req.txt b/morozov_vladimir_lab_3/service_paints/req.txt new file mode 100644 index 0000000..d89375d --- /dev/null +++ b/morozov_vladimir_lab_3/service_paints/req.txt @@ -0,0 +1,4 @@ +fastapi[all] +uuid +uvicorn +requests \ No newline at end of file diff --git a/morozov_vladimir_lab_4/Teacher_student_message/FirstTest.png b/morozov_vladimir_lab_4/Teacher_student_message/FirstTest.png new file mode 100644 index 0000000..60e2f3d Binary files /dev/null and b/morozov_vladimir_lab_4/Teacher_student_message/FirstTest.png differ diff --git a/morozov_vladimir_lab_4/Teacher_student_message/FirstTest_Cool.png b/morozov_vladimir_lab_4/Teacher_student_message/FirstTest_Cool.png new file mode 100644 index 0000000..0d883f8 Binary files /dev/null and b/morozov_vladimir_lab_4/Teacher_student_message/FirstTest_Cool.png differ diff --git a/morozov_vladimir_lab_4/Teacher_student_message/FirstTest_Normal.png b/morozov_vladimir_lab_4/Teacher_student_message/FirstTest_Normal.png new file mode 100644 index 0000000..0df1ba0 Binary files /dev/null and b/morozov_vladimir_lab_4/Teacher_student_message/FirstTest_Normal.png differ diff --git a/morozov_vladimir_lab_4/Teacher_student_message/SecondTest.png b/morozov_vladimir_lab_4/Teacher_student_message/SecondTest.png new file mode 100644 index 0000000..a2dcfa2 Binary files /dev/null and b/morozov_vladimir_lab_4/Teacher_student_message/SecondTest.png differ diff --git a/morozov_vladimir_lab_4/Teacher_student_message/SecondTestNormal.png b/morozov_vladimir_lab_4/Teacher_student_message/SecondTestNormal.png new file mode 100644 index 0000000..4f2588f Binary files /dev/null and b/morozov_vladimir_lab_4/Teacher_student_message/SecondTestNormal.png differ diff --git a/morozov_vladimir_lab_4/Teacher_student_message/Student_Cool.py b/morozov_vladimir_lab_4/Teacher_student_message/Student_Cool.py new file mode 100644 index 0000000..5f406b3 --- /dev/null +++ b/morozov_vladimir_lab_4/Teacher_student_message/Student_Cool.py @@ -0,0 +1,24 @@ +import pika + +connection = pika.BlockingConnection( + pika.ConnectionParameters(host='localhost')) +channel = connection.channel() +channel.basic_qos(prefetch_count=1) +channel.exchange_declare(exchange='grade_book', exchange_type='fanout') + +result = channel.queue_declare(queue='cool_student', exclusive=True) +queue_name = result.method.queue + +channel.queue_bind(exchange='grade_book', queue=queue_name) + +print(' [*] Waiting for logs. To exit press CTRL+C') + +def callback(ch, method, properties, body): + print(f" [x] Receive: {body}") + print(f" [+] Complete: {body}") + ch.basic_ack(delivery_tag=method.delivery_tag) + +channel.basic_consume( + queue=queue_name, on_message_callback=callback) + +channel.start_consuming() \ No newline at end of file diff --git a/morozov_vladimir_lab_4/Teacher_student_message/Student_Normal.py b/morozov_vladimir_lab_4/Teacher_student_message/Student_Normal.py new file mode 100644 index 0000000..20d3e1b --- /dev/null +++ b/morozov_vladimir_lab_4/Teacher_student_message/Student_Normal.py @@ -0,0 +1,31 @@ +import random +import time + +import pika + +connection = pika.BlockingConnection( + pika.ConnectionParameters(host='localhost')) +channel = connection.channel() + +channel.basic_qos(prefetch_count=1) + +channel.exchange_declare(exchange='grade_book', exchange_type='fanout') + +result = channel.queue_declare(queue='normal_student', durable=True) + +queue_name = result.method.queue + +channel.queue_bind(exchange='grade_book', queue=queue_name) + +print(' [*] Waiting for tasks. To exit press CTRL+C') + +def callback(ch, method, properties, body): + print(f" [x] Receive: {body}") + time.sleep(random.randint(2,4)) + print(f" [+] Complete: {body}") + ch.basic_ack(delivery_tag=method.delivery_tag) + +channel.basic_consume( + queue=queue_name, on_message_callback=callback) + +channel.start_consuming() \ No newline at end of file diff --git a/morozov_vladimir_lab_4/Teacher_student_message/teacher.py b/morozov_vladimir_lab_4/Teacher_student_message/teacher.py new file mode 100644 index 0000000..6d55c8e --- /dev/null +++ b/morozov_vladimir_lab_4/Teacher_student_message/teacher.py @@ -0,0 +1,25 @@ +import sys +import time + +import pika + +connection = pika.BlockingConnection( + pika.ConnectionParameters(host='localhost')) +channel = connection.channel() + +channel.exchange_declare(exchange='grade_book', + exchange_type='fanout') + +count = 0 +while True: + count+= 1 + time.sleep(1) + message = f"Homework #{count}" + channel.basic_publish(exchange='grade_book', + routing_key='', + body=message, + properties=pika.BasicProperties( + delivery_mode=pika.DeliveryMode.Persistent + )) + print(f" [x] Sent {message}") + diff --git a/morozov_vladimir_lab_4/lesson_1/img.png b/morozov_vladimir_lab_4/lesson_1/img.png new file mode 100644 index 0000000..6c103ae Binary files /dev/null and b/morozov_vladimir_lab_4/lesson_1/img.png differ diff --git a/morozov_vladimir_lab_4/lesson_1/receive.py b/morozov_vladimir_lab_4/lesson_1/receive.py new file mode 100644 index 0000000..f118e0a --- /dev/null +++ b/morozov_vladimir_lab_4/lesson_1/receive.py @@ -0,0 +1,25 @@ +import pika, sys, os + +def main(): + connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost')) + channel = connection.channel() + + channel.queue_declare(queue='hello') + + def callback(ch, method, properties, body): + print(f" [x] Received {body}") + + channel.basic_consume(queue='hello', on_message_callback=callback, auto_ack=True) + + print(' [*] Waiting for messages. To exit press CTRL+C') + channel.start_consuming() + +if __name__ == '__main__': + try: + main() + except KeyboardInterrupt: + print('Interrupted') + try: + sys.exit(0) + except SystemExit: + os._exit(0) \ No newline at end of file diff --git a/morozov_vladimir_lab_4/lesson_1/send.py b/morozov_vladimir_lab_4/lesson_1/send.py new file mode 100644 index 0000000..41cfff2 --- /dev/null +++ b/morozov_vladimir_lab_4/lesson_1/send.py @@ -0,0 +1,11 @@ +import pika + +connection = pika.BlockingConnection( + pika.ConnectionParameters(host='localhost')) +channel = connection.channel() + +channel.queue_declare(queue='hello') + +channel.basic_publish(exchange='', routing_key='hello', body='Hello World!') +print(" [x] Sent 'Hello World!'") +connection.close() \ No newline at end of file diff --git a/morozov_vladimir_lab_4/lesson_2/img.png b/morozov_vladimir_lab_4/lesson_2/img.png new file mode 100644 index 0000000..87f5a27 Binary files /dev/null and b/morozov_vladimir_lab_4/lesson_2/img.png differ diff --git a/morozov_vladimir_lab_4/lesson_2/new_task.py b/morozov_vladimir_lab_4/lesson_2/new_task.py new file mode 100644 index 0000000..c87ac4f --- /dev/null +++ b/morozov_vladimir_lab_4/lesson_2/new_task.py @@ -0,0 +1,18 @@ +import sys +import pika + +connection = pika.BlockingConnection( + pika.ConnectionParameters(host='localhost')) +channel = connection.channel() + +channel.queue_declare(queue='task_queue', durable=True) + +message = ' '.join(sys.argv[1:]) or "Hello World!" + +channel.basic_publish(exchange='', + routing_key="task_queue", + body=message, + properties=pika.BasicProperties( + delivery_mode = pika.DeliveryMode.Persistent + )) +print(f" [x] Sent {message}") \ No newline at end of file diff --git a/morozov_vladimir_lab_4/lesson_2/worker.py b/morozov_vladimir_lab_4/lesson_2/worker.py new file mode 100644 index 0000000..d6c601d --- /dev/null +++ b/morozov_vladimir_lab_4/lesson_2/worker.py @@ -0,0 +1,29 @@ +import time + +import pika, sys, os + +def main(): + connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost')) + channel = connection.channel() + channel.basic_qos(prefetch_count=1) + channel.queue_declare(queue='task_queue', durable=True) + def callback(ch, method, properties, body): + print(f" [x] Received {body.decode()}") + time.sleep(body.count(b'.')) + print(" [x] Done") + ch.basic_ack(delivery_tag=method.delivery_tag) + + channel.basic_consume(queue='task_queue', on_message_callback=callback) + + print(' [*] Waiting for messages. To exit press CTRL+C') + channel.start_consuming() + +if __name__ == '__main__': + try: + main() + except KeyboardInterrupt: + print('Interrupted') + try: + sys.exit(0) + except SystemExit: + os._exit(0) \ No newline at end of file diff --git a/morozov_vladimir_lab_4/lesson_3/img.png b/morozov_vladimir_lab_4/lesson_3/img.png new file mode 100644 index 0000000..535b0a5 Binary files /dev/null and b/morozov_vladimir_lab_4/lesson_3/img.png differ diff --git a/morozov_vladimir_lab_4/lesson_3/receiver.py b/morozov_vladimir_lab_4/lesson_3/receiver.py new file mode 100644 index 0000000..60d881d --- /dev/null +++ b/morozov_vladimir_lab_4/lesson_3/receiver.py @@ -0,0 +1,22 @@ +import pika + +connection = pika.BlockingConnection( + pika.ConnectionParameters(host='localhost')) +channel = connection.channel() + +channel.exchange_declare(exchange='logs', exchange_type='fanout') + +result = channel.queue_declare(queue='', exclusive=True) +queue_name = result.method.queue + +channel.queue_bind(exchange='logs', queue=queue_name) + +print(' [*] Waiting for logs. To exit press CTRL+C') + +def callback(ch, method, properties, body): + print(f" [x] {body}") + +channel.basic_consume( + queue=queue_name, on_message_callback=callback, auto_ack=True) + +channel.start_consuming() \ No newline at end of file diff --git a/morozov_vladimir_lab_4/lesson_3/send.py b/morozov_vladimir_lab_4/lesson_3/send.py new file mode 100644 index 0000000..4b9d7c1 --- /dev/null +++ b/morozov_vladimir_lab_4/lesson_3/send.py @@ -0,0 +1,20 @@ +import sys +import pika + +connection = pika.BlockingConnection( + pika.ConnectionParameters(host='localhost')) +channel = connection.channel() + +channel.exchange_declare(exchange='logs', + exchange_type='fanout') + +message = ' '.join(sys.argv[1:]) or "Hello World!" + +channel.basic_publish(exchange='logs', + routing_key='', + body=message, + properties=pika.BasicProperties( + delivery_mode=pika.DeliveryMode.Persistent + )) + +print(f" [x] Sent {message}") \ No newline at end of file diff --git a/morozov_vladimir_lab_4/readme.md b/morozov_vladimir_lab_4/readme.md new file mode 100644 index 0000000..f027475 --- /dev/null +++ b/morozov_vladimir_lab_4/readme.md @@ -0,0 +1,44 @@ +# Лабораторная работа №4 - Работа с брокером сообщений + +## Прохождение уроков + +Урок №1. +![img.png](lesson_1%2Fimg.png) + +Урок №2. +![img.png](lesson_2%2Fimg.png) + +Урок №3. +![img.png](lesson_3%2Fimg.png) + +Все приложения были разработаны на Python + +## Разработанные приложения +В качестве предметной области было выбрано общение учителя и его учеников. Учитель дает задание ученикам, а они их выполняют. Я выделил 2 вида учеников: обычные, которым нужно некоторое время на то, чтобы выполнить задание; крутые ученики, которые выполняют задание моментально, как только получают его. +Были созданы следующие приложения: +- teacher - программа, которая представляет учителя и отправляет задания ученикам +- Student_Normal - программа, которая представялет обычного ученика, получает и обрабатывает, с задержкой, полученные задания. +- Student_Cool - программа, которая представялет крутого ученика, получает и моментально обрабатывает полученные задания. +Все программы были разработаны на языке Python. +Проведенные тесты: +#### Тест №1. Запущены 1 учитель, 1 обычный ученик, 1 крутой ученик: +![FirstTest.png](Teacher_student_message%2FFirstTest.png) +Показатели очереди обычного ученика: +![FirstTest_Normal.png](Teacher_student_message%2FFirstTest_Normal.png) +Показатели очереди крутого ученика: +![FirstTest_Cool.png](Teacher_student_message%2FFirstTest_Cool.png) + +Вывод: одного обычного ученика не хватает на то, чтобы выполнять все полученные в срок, ему тяжело :( +Крутому же ученику все дается с легкостью. + +#### Тест №2. Запущены 1 учитель, 4 обычных ученика: +![SecondTest.png](Teacher_student_message%2FSecondTest.png) +Показатели очереди обычного ученика: +![FirstTest_Normal.png](Teacher_student_message%2FFirstTest_Normal.png) +Вывод: если 4 обычных ученика объединяться и будут делать задания вместе, то они смогут избежать переполнения очереди заданий. + + + + +## Запись тестирования +Работа приложения представлена в [видео](https://disk.yandex.ru/i/zzwvXXpZhavh7A) \ No newline at end of file