Temporal.io по русски. Вступительное видео.

https://t.me/temporal_io

Расшифровка вступительного видео по Temporal with Java

0:00
ладно пойдем Дмитрий начнем хорошо ты можешь просто
0:06
перейти к следующему слайду
0:12
так что да, давайте просто начнем с самого начала, мы говорим, что Temporal
0:18
движок рабочего процесса, но что это вообще значит, потому что рабочего процесса много
0:24
двигателей на рынке и как вообще это слово для многих
0:29
людей означает что-то из похожего бизнес-домена, что используется как гм
0:35
люди бизнес-уровня для создания рабочих процессов высокого уровня, обычно в графических редакторах и т. д.
0:42
Temporal очень отличается от большинства подобных решений рабочего процесса, потому что, как мы
0:47
всегда говорим, что Temporal рабочий процесс — это код, поэтому наши основные пользователи и наша основная цель
0:56
инженеры и инженеры приложения гм и это
1:02
как мы сильно отличаемся с точки зрения нашего позиционирования с точки зрения нашего использования
1:07
кейсы из множества других движков рабочего процесса и э-э
1:14
как просто так есть много приложений потенциальных приложений рабочего процесса, но
1:20
в связи с сегодняшней встречей и обсуждением давайте просто сосредоточимся на одном из
1:26
довольно популярная проблема, которая у нас есть в настоящее время в целом в нашем сообществе и в
1:32
наших проектах — это микросервисная архитектура, когда у нас есть микросервисная архитектура
1:39
нам довольно часто приходится вносить последовательные изменения в
1:45
через микросервисы через несколько баз данных через несколько конечных точек и т. д.
1:52
и в основном типичные закономерности и типовые решения проблемы
1:57
сага, основанная либо на оркестровке, либо на хореографии
2:03
так что очень хорошей проблемой для механизма рабочего процесса является
2:08
на самом деле шаблон оркестровки в микросервисах, когда у нас в основном есть
2:14
некий центральный компонент, центральный игрок в системе, выполняющий последовательность действий в
2:21
среда микросервисов и настройка [Музыка]
2:27
этот шаблон и этот подход имеют много проблем, потому что
2:34
все может выйти из строя каждый шаг может выйти из строя внутри
2:39
сети распределенных транзакций или распределенных процессов может выйти из строя
2:46
и сам оркестратор, выполняющий изменения, может выйти из строя
2:52
и мы, как инженеры, в каждом проекте, к которому мы приходим, воспроизводим более или менее одно и то же
3:01
система той же архитектуры для восстановления из ситуаций
3:08
мы создаем реплики и брокеры сообщений
3:13
мы создаем какое-то постоянное состояние, которое позволяет нам восстанавливаться, когда что-то идет
3:20
неправильно мы создаем zookeeper, чтобы иметь возможность масштабироваться и иметь возможность
3:31
распределить работу в кластере, когда мы получим, когда наш проект получит какой-либо
3:37
значительная нагрузка, поэтому в основном все микросервисы
3:43
архитектура и подход более или менее воспроизводят ту же установку, что и
3:49
тот же набор проблем это дорого это запутанно это
3:56
трудно поддерживать для devops, а также чрезвычайно сложно
4:06
с точки зрения наблюдаемости и с точки зрения фактического письма, а не
4:12
просто вызывая конечные точки и выполняя действия, мы должны запланировать события
4:19
мы должны написать весь код, который обрабатывает все виды отказов и
4:26
восстанавливается из всех видов несогласованных состояний и т. д.
4:32
поэтому Temporal в основном обеспечивает решение для всех видов проблем, которые
4:39
может случиться в такой среде, у храма есть
4:45
два компонента Temporal сервер и Temporal SDK, поэтому
4:51
это SDK может быть для разных языков, но все они обеспечивают более или менее одинаковую функциональность
4:58
а Temporal сервер предоставляет возможность хранить состояние рабочего процесса
5:05
как сериализованное представление того, что на самом деле произошло в рабочем процессе
5:11
и мы называем это также историей
5:18
Temporal сервер предоставляет возможность планировать запуск триггеров в будущем
5:25
вы, наверное, знаете все ситуации, когда вдруг ваш проект нуждается в
5:32
что-то вроде э-э, мне нужно выполнить это завтра, и мы начинаем либо приносить все виды
5:39
дополнительные компоненты в систему, такие как планировщики или, что еще хуже, написать наш
5:44
собственный, особенно если нам нужно работать с большим количеством событий
5:50
поэтому Temporal сервер предоставляет возможность планировать запуск триггеров в будущем.
5:59
Temporal SDK предоставляют возможность на самом деле
6:05
сериализовать выполнение вашего кода как историю как последовательность событий
6:12
а также обеспечивает серию абстракций рабочего процесса
6:17
рабочие процессы и действия для фактического масштабирования и выполнения кода, чтобы
6:24
это фреймворк для выполнения кода
6:31
так что я могу перейти к следующему слайду
6:36
давайте просто погрузимся в очень конкретный пример очень конкретного
6:43
очень простой рабочий процесс и как этот рабочий процесс может быть даже
6:49
сериализуется в некоторое последовательное представление
6:54
Итак, здесь у нас есть очень простая функция, которая
7:00
проверяет и обновляет статус учетной записи пользователя и после этого спит в течение 30
7:07
дней, так что в основном здесь мы просто воспроизводим что-то вроде
7:12
каждый месяц нам нужно выполнить какое-то действие над пользователем и после этого ждать следующего месяца
7:20
хм, это можно представить как всего три строки кода, это цикл, это
7:28
действие, которое вам нужно выполнить, и это
7:34
и справа от кода видно, как это может быть представлено на самом деле
7:41
как настойчивая серия действий, давайте просто пройдемся, чтобы дать некоторые
7:49
понять, что происходит, как работает Temporal код и как этот простой код может быть
7:58
в основном сериализуется в состояние в базе данных
8:03
когда вы планируете рабочий процесс вашего клиента
8:09
отправить на сервер команду, которая создает новый рабочий процесс, новую историю для этого рабочего процесса, которая
8:16
в основном выполнение рабочего процесса началось, как вы видите в первой строке, в которой есть все, что
8:23
нужен для запуска рабочего процесса и в основном это входные параметры рабочего процесса
8:30
после того, как Temporal сервер для вас запланирует выполнение этого рабочего процесса
8:38
путем планирования того, что мы называем задачей рабочего процесса, задача рабочего процесса в основном представляет собой сущность
8:45
который представляет собой триггер пользовательского кода, который этот триггер создает, когда
8:52
есть какая-либо причина разблокировать пользовательский код, это либо начало выполнения
8:58
ваш код или его фактический запуск по любой причине, например, из-за
9:06
истечение таймера сна или какой-либо входящий сигнал
9:11
поэтому Temporal сервер создает задачу рабочего процесса и планирует ее
9:17
это то, что происходило в сети номер два после Temporal работника, что на самом деле
9:25
выполняет этот код и размещает этот код гм
9:30
берет событие с сервера, и это момент, когда Temporal
9:38
сервер регистрирует, что выполнение этой задачи рабочего процесса действительно началось
9:44
гм, ваш код на рабочем получает шанс
9:51
чтобы фактически начать выполнение, и он вызывает активность
9:59
так что статус обновления точки действия пользователя здесь в основном является вызовом части
10:05
код, который может выполняться на отдельной машине
10:11
вы хотите вызвать его, и вы хотите сохранить возврат
10:16
ценность этой деятельности — это то, что происходит в истории в следующем фрагменте истории, когда
10:23
сервер храма регистрирует завершение задачи оракула
10:28
почему, поскольку рабочий процесс прямо сейчас заблокирован, запланировано действие и
10:35
ему нужно дождаться своего результата, поэтому, когда код рабочего процесса заблокирован, он
10:40
означает, что это завершение задачи рабочего процесса, и поток выполнения освобождается
10:49
после этого действие фактически запланировано сервером, его подхватывает рабочий
10:55
и рабочий выполняет код в действии, поэтому
11:01
он создает последовательность событий, только что начатых действий, запланированных, начатых, завершенных.
11:08
и когда действие завершено, это означает, что код пользовательского рабочего процесса может продолжить выполнение
11:15
потому что у него есть какой-то триггер, который завершает выполнение действия до
11:21
продолжать продвижение, когда сервер храма планирует запуск нового рабочего процесса при событиях, которые получают
11:28
подхватывается кодом рабочего процесса, который теперь видит, что действие выполнено
11:35
и он переходит в следующую строку, которая ждет 30 секунд в течение 30 дней.
11:42
когда это происходит снова, код рабочего процесса блокируется и
11:48
выполнение освобождается, а задача рабочего процесса получает
11:55
завершено, и давайте отправим отчет на сервер, чтобы получить
12:01
с этим завершением мы также говорим серверу, что нам нужен таймер на 30 дней
12:10
и это то, что записывается в последней строке истории, так что
12:15
история фактически фиксирует факт наличия таймера в этом рабочем процессе
12:21
это должно быть запущено через 720 часов, и Temporal сервер позаботится об этом
12:30
через месяц, когда это произойдет, почему это представляет это представление
12:38
так могущественен и так велик всякий раз, когда мы терпим неудачу на любом этапе этого
12:45
мы можем восстановить состояние нашего рабочего процесса
12:51
путем повторного выполнения этого кода и подачи этой истории событий
12:57
чтобы фактически восстановить рабочий процесс в том состоянии, в котором мы его оставили
13:04
где это не удалось, например, если в следующем месяце кто-то перезагрузит
13:10
сервер, который, скорее всего, будет работать, когда таймер тикает и
13:18
запускает выполнение Temporal SDK, на самом деле сможет
13:24
забрать историю с сервера и восстановить код в том состоянии, в котором мы
13:32
осталось, это одна из основных функций SDKs в Temporal, так что это
13:41
в основном обеспечивает уровень соединения между
13:46
пользовательский код и эти сохраненные события истории и
13:53
таймеры на стороне сервера есть вопросы по этому экрану
13:59
потому что происходит много всего, да, у меня есть вопрос
14:04
так это на самом деле рабочий фрагмент кода слева
14:12
у него было это, я имею в виду, чтобы вывести вывод справа, мне пришлось написать его и запустить
14:18
это так э-э, так Temporal каким-то образом сохранило
14:24
снимок состояния функции да восстанавливать или нет как как код
14:30
продолжится в месяце с кодовой строки
14:36
пять, я не знаю, да, в следующем цикле, как это произойдет
14:41
Итак, давайте представим, что кто-то отключил наш сервер посередине
14:47
нет способа сохранить состояние процесса
14:53
это не разумный способ, который мы можем использовать в производстве, так что
14:59
это сериализованное представление используется для того, что мы называем повторным воспроизведением.
15:06
поэтому мы знаем, что есть рабочий процесс, который сохраняется в базе данных.
15:12
а Temporal сервер через месяц, когда тикает таймер, фактически запланирует новый рабочий процесс
15:20
задача для выполнения на воркере и когда этот воркер получит задачу
15:26
чтобы выполнить его, вы обнаружите, что нет рабочего процесса
15:31
как будто мне нужно восстановиться, и то, что он делает, приносит все
15:37
история с сервера, он берет код, и он в основном соответствует истории для
15:44
код, например, здесь, что произойдет в первой строке в основном
15:50
вызывает действие прямо, когда вместо фактического вызова и
15:55
активность Temporal SDK мы посмотрим на историю и увидим, что эта активность была
16:00
уже выполнено, поэтому мне не нужно повторять шаг и
16:06
он просто будет использовать возвращаемое значение, записанное в истории
16:12
поэтому история сохраняет результаты каждой операции, такой как активность
16:20
выполнение, поэтому использование кода истории будет буквально воспроизводиться до состояния
16:29
там, где мы его оставили, и после этого он продолжит выполнение
16:34
это имеет смысл, потому что это немного сложно
16:39
концепция, и хм, важно понимать, что Temporal не имеет волшебства
16:46
возможность просто сохранить состояние рабочего процесса в настоящее время, которое в настоящее время
16:52
существует в памяти, когда ему нужно восстановить состояние, он должен снова выполнить код
17:00
на основе и использовать историю, которая была сохранена, чтобы восстановить состояние
17:13
ладно ладно так а
17:19
хорошо, спасибо, да, так что это просто важно
17:24
понять, что Temporal SDK существует, чтобы в основном обеспечить именно эту возможность
17:30
когда вы вызываете действие, это вызов действия, которого нет
17:36
просто вызов вашего кода, этот вызов фактически перехватывается
17:41
SDK и активность были запланированы на работника, но
17:47
это не обязательно, если оно уже было выполнено, если оно уже было выполнено в
17:53
в этом случае SDK знает, что он не должен быть редким и
17:58
вместо этого будет использоваться постоянное состояние, поэтому Temporal SDK предоставляет эти способы для
18:08
в основном перехватывать контроль над кодом, чтобы обеспечить гарантии того, что мы
18:15
пытаясь обеспечить
18:21
о, спасибо, я думаю, что дальнейшие примеры также будут полезны для меня, так что спасибо
18:27
за ваши ответы, да, конечно, вы хотите бежать, используйте их, подумайте об этом, как
18:34
Дмитрий объяснил, как это делается, но когда вы пишете свои рабочие процессы, вас это не должно волновать, это хорошо понимать
18:40
но когда вы пишете свой рабочий процесс, вы можете просто вызвать сон рабочего процесса на 30 дней, и он просто работает, вы можете думать о том, чтобы относиться к нему как к волшебству, вы можете понять волшебство, но
18:47
когда вы пишете рабочий процесс, вам все равно, это просто то, как вы думаете о своем коде, не может
18:54
поскольку он не привязан к конкретной машине, его всегда можно восстановить, это своего рода виртуальное право, как будто это не так.
18:59
связанный с определенными блоками, что угодно может выйти из строя, ваш код остается самой важной причиной, почему это очень
19:07
хорошо понимать, что эта лежащая в основе абстракция истории
19:12
потому что код рабочего процесса имеет набор ограничений, что мы обычно говорим, что рабочий процесс
19:19
код должен быть детерминированным, что обычно означает, что должно быть
19:24
отсутствие генерации случайных значений прямо в коде рабочего процесса, кроме использования
19:33
генераторы, которые предоставляет Temporal SDK, или не должно быть модификации
19:40
код рабочего процесса для уже запущенных рабочих процессов без учета детерминизма
19:47
хотели бы понять эту концепцию и ограничения, которые мы накладываем на рабочий процесс
19:52
код, очень полезно понять, как он сериализуется
19:57
потому что если нет понимания механика стерилизации
20:03
вероятно, эти ограничения будут выглядеть искусственными, но у Temporal SDK есть ограничения на
20:11
код рабочего процесса, и это основная причина, потому что он должен быть
20:19
воспроизводимым мы будем, мы должны быть в состоянии использовать записанную историю, чтобы восстановить
20:24
государство тифа ты хочешь
20:29
пойдите с примером, конечно, у меня есть, может быть, еще один два слайда
20:35
только самые простые, а затем перейдите в демоверсию, и мы можем обсудить все это вместе, если вы не против
20:45
эм ладно эм да ну так что спасибо это было круто я имею в виду
20:51
divitry действительно может объяснить это таким образом, что это просто потрясающе, у меня есть только пара
20:58
небольшие слайды номер один, я просто хотел поговорить о самом java SDK
21:04
точно так же, как другие SDK, которые предоставляют Temporal, они очень ненавязчивы, что означает, что вы знаете конкретно
21:10
мы говорим о java, вы действительно можете использовать его в любой среде, это просто библиотека, которую вы
21:17
включите, и вы можете начать использовать его, независимо от того, что у вас есть, если вы создаете новый
21:23
приложения или если у вас есть что-нибудь существующее, например, приложения, которые вы хотели добавить
21:29
рабочие процессы и Temporal процессы на основе модели программирования
21:34
Конечно, это ты знаешь
21:40
можно повторно использовать существующую среду разработки, чтобы вы могли продолжать использовать свои идеи
21:45
хотя, конечно, мы говорим, что темп — это решение рабочего процесса, обычно вы знаете, что люди думают, что
21:51
вы должны принять какие-то пользовательские решения и пользовательские среды и бла-бла-бла с важным, что не
21:57
случае, вы все еще можете использовать свои идентификаторы, которые вы все еще можете развернуть, вы знаете, kubernetes docker или что-то еще
22:04
платформа, которую вы используете в настоящее время или думаете о запуске в будущем
22:09
и то же самое с тестированием и отладкой, вы можете, конечно
22:15
как мы увидим с нашим SDK, вы используете junit четыре и пять, вы можете издеваться над
22:20
вы знаете действия и подобные вещи, и и и действительно пишете свой тест, как и рабочие процессы тестирования
22:28
наряду с вашими тестами, которые у вас уже могут быть в настоящее время тестировать другую часть ваших систем
22:33
а также просто для того, чтобы вы знали, начните, и если вы хотите сделать скриншот этого и
22:40
конечно, вы будете на ютубе позже, вы знаете, одна из вещей, о которых я хотел поговорить, это как
22:46
вы начинаете, конечно, у нас есть наша Temporal документация, специально для java SDK, у нас есть
22:53
репозиторий примеров github, который включает в себя массу различных образцов и
22:58
я думаю, что он растет, список образцов становится больше, и мы действительно прислушиваемся к нашему сообществу, насколько это возможно.
23:05
вопросы, которые у них есть, и и и пытаются предоставить полезные образцы, они выбегают из коробки.
23:12
для вас, чтобы получить представление обо всех различных функциях, которые предоставляет Temporal java SDK
23:19
у нас также есть семинары, у нас было два до сих пор, и один в начале следующей недели, и вот URL и
23:27
и на этих семинарах мы как бы углубляемся в конкретные случаи
23:32
так что, если у вас есть какие-либо вопросы, которые вы знаете, подумайте, хотите ли вы узнать о чем-то еще
23:38
продвинутые концепции Temporal хранения в Java SDK, к которым вы обязательно присоединитесь
23:43
там и задавайте любые вопросы, и, конечно же, у нас есть тонна видео на YouTube, и мы добавляем их
23:49
мы создаем все больше и больше контента, наш ютуб растет так сильно, я
23:54
уверен, вы найдете ряд видео, которые помогут вам начать работу
23:59
гм, так что, насколько хорошо, мы говорили о том, что, как вы знаете, делает SDK и как работает Temporal
24:06
и история, но как бы возвращаясь назад, как вы на самом деле начинаете использовать java SDK в моем проекте?
24:12
вы знаете, что это зависит от вашей системы сборки для gradle, вы просто добавляете пару зависимостей, ну большинство
24:19
важным является Temporal SDK, и здесь у нас есть версия 181, которая является
24:24
последнее и, может быть, Дмитрий может рассказать о том, когда он выпустит, вы знаете, одну девятку и тому подобное, и что за
24:32
временная шкала выглядит как в настоящее время, но да, Temporal зависимость dash SDK действительно похожа на
24:38
основная зависимость SDK включает в себя все API для написания вашего клиента
24:43
код, который вызывает рабочие процессы, чтобы фактически написать ваш рабочий процесс
24:49
код и использование всех видов конструкций, которые вам нужно использовать для
24:54
напиши свой рабочий процесс оркестровки и Дмитрий также коснулся этого хм
25:00
и вы знаете такие вещи, это также гм
25:05
включает в себя много других вещей, вроде более продвинутых, но мы поговорим об этом позже, и, конечно же, вам нужно
25:11
Зависимость от тестирования Зависимость от тестирования позволяет вам иметь полный
25:17
среда тестирования, которая находится в памяти, поэтому вам не нужно иметь
25:22
запуск Temporal сервера, работающего для фактического запуска ваших тестов
25:30
тестирование SDK заключается в том, что у него есть что-то вроде расширенной функции времени, так что даже
25:35
если бы вы, например, как Дмитрий, показали вес своего рабочего процесса за 30 дней, э-э, ваше
25:40
тест может выполняться за миллисекунды, поэтому вы действительно можете использовать рабочий процесс, который мы показали на предыдущем слайде, и и
25:49
протестируйте его, может быть, год или два или любой другой период времени, который вы хотите, и вы, конечно, не можете проверить его в течение
25:55
миллисекунда, и вот, да, крутая проблема, я просто хочу, чтобы вопрос, который у нас есть, был полностью
26:04
полноразмерный сервер, такой как Temporal сервер, для которого требуется база данных и т. д., поэтому
26:10
относительно сложный для операций, у нас есть упрощенная настройка для
26:17
разработка с использованием только docker compose, с помощью которой очень легко запустить настоящий сервер
26:23
но также у нас есть тестовый сервер, чрезвычайно легкий в реализации памяти, который можно использовать для
26:31
модульные тесты, и он ведет себя очень близко к Temporal серверам производства
26:37
поэтому всякий раз, когда мы видим разницу, мы на самом деле исправляем ее, мы сохраняем ее синхронизированной с реальными вещами, поэтому
26:45
чрезвычайно легко использовать полную реализацию, полную реальную реализацию и Temporalнную реализацию в ваших модульных тестах.
26:53
круто, да, и просто чтобы показать вам то же самое для maven, если вы используете maven в качестве сборки
27:00
системе нужно всего две зависимости для настройки, и это то, что вы и так знаете
27:06
очень легко начать работу со стороны SDK в новом или
27:12
с существующими приложениями все в порядке, поэтому я постараюсь сделать очень быструю демонстрацию сейчас и
27:19
это очень похоже на то, что Дмитрий
27:26
о чем мы говорили на своем слайде, это немного отличается, как вы знаете
27:32
не синхронизировался полностью на этом, и это не имеет большого значения, но
27:37
вы знаете, что это делает, у нас есть очень простой метод рабочего процесса, который очень похож на тот же, что и на
27:43
слайд в основном в нашем рабочем процессе в этом случае вместо использования одной учетной записи или
27:50
или идентификатор пользователя, и я буду обновлять его каждые 30 дней в нашем тесте, у нас есть номер учетной записи
27:58
идентификаторы, которые мы получаем, вы знаете, либо от конечных пользователей, либо в ваших приложениях kcp, кто-то может
28:05
войти в какой-то веб-интерфейс и и использовать его в качестве входных данных для вашего э-э
28:11
рабочий процесс как данные, и что мы делаем, мы в основном
28:16
цикл по каждому из наших идентификаторов учетной записи, и для каждого из наших идентификаторов учетной записи мы
28:21
хотите уведомить его о некоторой информации, и это всего лишь небольшая демонстрация
28:26
но только на предыдущем слайде мы показали, что мы вызываем нашу активность
28:32
наша деятельность дмитрий хм объяснил, можно рассматривать как удаленный вызов процедуры, так что это
28:38
будет обрабатываться его планирование, и это будет обрабатываться Temporal сервером, а это
28:44
деятельность снова может быть, как сказал дмитрий, выполнена на совершенно другом
28:50
работник или вы знаете другую службу, в которой они могут размещать эту деятельность, и имеет
28:55
рабочий, который зарегистрировал его, и после того, как это действие завершится, мы просто ради этой демонстрации
29:02
поспите две секунды, и вы поймете, почему это
29:08
гм, у нас также есть, конечно, мы используем Temporal SDK в нашем работнике, поэтому оба
29:16
рабочий процесс, и наш рабочий, и, как вы видели, наш тип стартера, который мы называем
29:21
стартеры или клиентское приложение, где мы хотим вызвать выполнение нашего рабочего процесса, все эти вещи используют Temporal
java SDK, так что вы ничего не знаете, что вам нужно получить дополнительно, чтобы написать работника, вам не нужно ничего получать
29:34
дополнительно, чтобы написать какой-то API для вызова ваших рабочих процессов, весь вид grpc под капотом, э-э
29:42
связь между вашим кодом и Temporal сервером
29:47
обрабатывается нашей Temporal Java
37:09
клиенты учитывают гм правильно и это
37:14
это слово все в порядке, так что это похоже на то, что у меня было, как на этом последнем слайде, который я
37:20
хотел показать, что мы приветствуем всех в сообществе
37:25
пожалуйста, вы знаете, что нам нужен ваш вклад, мы хотели бы получить ваш вклад, мы любим получать гм
37:32
твои твои мысли как ты используешь Temporal как ты используешь java SDK какие у тебя проблемы
37:37
сталкиваться, и лучший способ принять участие, конечно, на github и
37:43
вот URL-адрес нашего репозитория java SDK github
37:48
у нас есть форум, важное сообщество, которым я обязан, и я настоятельно рекомендую вам, если у вас есть какие-либо
37:54
вопросы, которые вы знаете, вопросы для начинающих, чтобы действительно понять наши вопросы, мы всегда готовы ответить и помочь вам
38:00
там, ну, и, конечно, наш Temporal запас — это запас, и мы специально для java у нас есть э-э
38:08
SDK есть java-канал, к которому вы можете присоединиться, и, и вы знаете, участвуйте в сообществе, чтобы вы знали и видели
38:14
а также не только задавать вопросы, но и читать о других людях и о том, как они используют Temporal файлы в java SDK.
38:22
[Музыка]

Добавить комментарий

Ваш адрес email не будет опубликован.