В рамках домашней работы требуется реализовать систему Агрегатора Билетов в Кино, состоящую из трех взаимодействующих друг с другом сервисов: Ticket Service, Film Service, Cinema Service.
Ниже описано публичное API, оно описывает методы, предоставляемые пользователю. Внутреннюю коммуникацию между сервисами вы проектируете и реализуете сами.
- Ticket Service – 8080;
- Film Service – 8070;
- Cinema Service – 8060;
Полное описание публичного API приведено в спецификации OpenAPI.
GET {{filmsUrl}}/api/v1/films?page=1&size=10
Accept: application/json
GET {{cinemaUrl}}/api/v1/cinema?page=1&size=10
Accept: application/json
GET {{cinemaUrl}}/api/v1/cinema/{{cinemaUid}}/films
Accept: application/json
Запрос приходит на Ticket Service, в Cinema Service выполняется
проверка film_session.total_seats
> film_session.booked_seats
, если все успешно, то film_session.booked_seats
увеличивается на 1 и в Ticket Service создается ticket со статусом BOOKED
.
POST {{ticketUrl}}/api/v1/tickets/cinema/{{cinemaUid}}/films/{{filmUid}}
Content-Type: application/json
Accept: application/json
X-User-Name: {{username}}
{
"date": "2024-01-01T08:00:00",
"row": 10,
"seat": 15
}
В ответ приходит:
201 Created
и ссылка на билет в заголовке Location: /api/v1/tickets/{ticketUid}
GET {{ticketUrl}}/api/v1/tickets/{{ticketUid}}
Accept: application/json
X-User-Name: {{username}}
В ответ приходит:
{
"ticketUid": "<ticketUid>",
"status": "BOOKED",
"date": "2024-01-01T08:00:00",
"seat": 15,
"row": 10
}
В Ticket Service выполняется поиск билета по ticketUid
, проверяется что до начала сеанса больше 1 часа, если условие
выполняется, то билет помечается CANCELED
, но не удаляется. Если до сеанса меньше 1 часа, то
возвращается 409 Conflict
.
DELETE {{ticketUrl}}/api/v1/tickets/{{ticketUid}}
Accept: application/json
X-User-Name: {{username}}
В ответ приходит:
204 No Content
с пустым телом ответа. Билет помечается как CANCELED
, но не удаляется.
Ниже приведено примерное описание структуры баз данных каждого сервиса, вы можете менять структуру таблиц, если считаете что она будет лучше ложиться на реализацию.
CREATE TABLE film
(
id SERIAL PRIMARY KEY,
film_uid uuid NOT NULL,
name VARCHAR(255) NOT NULL,
rating NUMERIC(8, 2) NOT NULL DEFAULT 10
CHECK ( rating BETWEEN 0 AND 10 ),
director VARCHAR(255),
producer VARCHAR(255),
genre VARCHAR(255) NOT NULL
);
CREATE UNIQUE INDEX udx_film_uid ON film (film_uid);
CREATE TABLE cinema
(
id SERIAL PRIMARY KEY,
cinema_uid uuid NOT NULL,
name VARCHAR(255),
address VARCHAR(255)
);
CREATE UNIQUE INDEX udx_cinema_uid ON cinema (cinema_uid);
CREATE TABLE film_session
(
id SERIAL PRIMARY KEY,
session_uid uuid NOT NULL,
film_uid uuid NOT NULL,
total_seats INT NOT NULL,
booked_seats INT NOT NULL DEFAULT 0
CHECK ( booked_seats < total_seats ),
date TIMESTAMP NOT NULL,
cinema_id INT
CONSTRAINT fk_film_session_cinema_id REFERENCES cinema (id)
);
CREATE UNIQUE INDEX udx_film_session_session_uid ON film_session (session_uid);
CREATE TABLE tickets
(
id SERIAL PRIMARY KEY,
ticket_uid uuid NOT NULL,
film_uid uuid NOT NULL,
session_uid uuid NOT NULL,
user_name VARCHAR(80) NOT NULL,
date TIMESTAMP NOT NULL,
status VARCHAR(20) NOT NULL
CHECK ( status IN ('BOOKED', 'CANCELED') )
);
CREATE UNIQUE INDEX udx_tickets_ticket_uid ON tickets (ticket_uid);
Для успешного прохождения тестов в базе в таблицах должны быть данные:
films:
- id: 1
film_uid: "049161bb-badd-4fa8-9d90-87c9a82b0668"
name: "Terminator 2 Judgment day"
rating: 8.6
director: "James Cameron"
producer: "James Cameron"
genre: "Sci-Fi"
cinema:
- id: 1
cinemaUid: "06cc4ba3-ee97-4d29-a814-c40588290d17",
name: "Кинотеатр Москва",
address: "Ереван, улица Хачатура Абовяна, 18"
film_session:
- id: 1
cinema_id: 1
film_uid: "049161bb-badd-4fa8-9d90-87c9a82b0668"
date: "2024-01-01T08:00:00"
total_seats: 5000
booked_seats: 0
- Каждый сервис имеет свое собственное хранилище, если оно ему нужно. Для локальной разработки можно использовать
Postgres 15 в docker, для этого нужно запустить
docker compose up postgres -d
, поднимется контейнер, будет создан пользовательprogram
:test
и 3 БД:films
,tickets
,cinema
. - Для межсервисного взаимодействия использовать HTTP (придерживаться RESTful).
- На каждом сервисе сделать специальный endpoint
GET /manage/health
, отдающий 200 ОК, он будет использоваться для проверки доступности сервиса (в Github Actions в скрипте проверки готовности всех сервисов wait-script.sh)../scripts/wait-for.sh -t 120 "http://localhost:$port/manage/health" -- echo "Host localhost:$port is active"
- Код хранить на Github, для сборки использовать Github Actions.
- Каждый сервис должен быть завернут в docker.
- В build.yml дописать шаги на сборку.
- Интеграционные тесты можно проверить локально, для этого нужно импортировать в Postman коллекцию collection.json] и environment local-env.json.
Для тестирования все сервисы поднимаются через docker compose и для них запускаются тесты.
- При получении задания у вас создается копия этого репозитория для вашего пользователя.
- После того как все тесты успешно завершатся, в Github Classroom на Dashboard будет отмечено успешное выполнение тестов.