Слайд 2
![Цель Поделиться подходом к неблокирующей отправке созданных пользователем данных на сервер](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-1.jpg)
Цель
Поделиться подходом к неблокирующей отправке созданных пользователем данных на сервер
Слайд 3
![О чём пойдёт речь Как «хорошо» отправлять данные на сервер:](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-2.jpg)
О чём пойдёт речь
Как «хорошо» отправлять данные на сервер:
концепция
варианты реализации
и ещё
пара рецептов
Слайд 4
![Чего не будет Транзакционность](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-3.jpg)
Чего не будет
Транзакционность
Слайд 5
![Интро Владимир Абакумов, TeamLead ОМР DIRECTUM и DirectumRX DIRECTUM Solo и Jazz](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-4.jpg)
Интро
Владимир Абакумов, TeamLead ОМР
DIRECTUM и DirectumRX
DIRECTUM Solo и Jazz
Слайд 6
![Отправка созданных пользователем данных Блокируем работу](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-5.jpg)
Отправка созданных пользователем данных
Блокируем работу
Слайд 7
![Отправка созданных пользователем данных Блокируем работу Просто и надежно Ответственность](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-6.jpg)
Отправка созданных пользователем данных
Блокируем работу
Просто и надежно
Ответственность на пользователе
Бесяче (╯ °
□ °) ╯ (┻━┻)
Слайд 8
![Отправка созданных пользователем данных Не блокируем работу](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-7.jpg)
Отправка созданных пользователем данных
Не блокируем работу
Слайд 9
![Когда узнаешь, что данные пропали](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-8.jpg)
Когда узнаешь, что данные пропали
Слайд 10
![Отправка созданных пользователем данных Не блокируем работу Не понятен статус](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-9.jpg)
Отправка созданных пользователем данных
Не блокируем работу
Не понятен статус
Слайд 11
![Отправка созданных пользователем данных Не блокируем работу Не понятен статус Можно потерять данные](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-10.jpg)
Отправка созданных пользователем данных
Не блокируем работу
Не понятен статус
Можно потерять данные
Слайд 12
![Отправка созданных пользователем данных Не блокируем работу Не теряем данные](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-11.jpg)
Отправка созданных пользователем данных
Не блокируем работу
Не теряем данные
Слайд 13
![Приложение для организации событий](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-12.jpg)
Приложение для организации событий
Слайд 14
![Приложение для организации событий Создаём событие, указывая реквизиты, участников Добавляем фото места Добавляем новых участников](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-13.jpg)
Приложение для организации событий
Создаём событие, указывая реквизиты, участников
Добавляем фото места
Добавляем новых
участников
Слайд 15
![Задачи Создать событие Добавить фото: Обработать фото (сжатие, фильтры); Отправить](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-14.jpg)
Задачи
Создать событие
Добавить фото:
Обработать фото (сжатие, фильтры);
Отправить файл на сервер и получить
URL;
Прикрепить к событию.
Добавить участников
Слайд 16
![Схема задач](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-15.jpg)
Слайд 17
![Схема задач](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-16.jpg)
Слайд 18
![Схема задач](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-17.jpg)
Слайд 19
![Схема задач](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-18.jpg)
Слайд 20
![Схема задач](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-19.jpg)
Слайд 21
![Схема задач](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-20.jpg)
Слайд 22
![Схема задач](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-21.jpg)
Слайд 23
![Схема задач](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-22.jpg)
Слайд 24
![Схема задач](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-23.jpg)
Слайд 25
![Схема задач](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-24.jpg)
Слайд 26
![Схема задач](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-25.jpg)
Слайд 27
![Схема задач](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-26.jpg)
Слайд 28
![Схема задач](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-27.jpg)
Слайд 29
![Отправка созданных пользователем данных Разбиваем задачи на атомарные подзадачи Сохранение](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-28.jpg)
Отправка созданных пользователем данных
Разбиваем задачи на атомарные подзадачи
Сохранение данных и состояния
задач
Семантически значимый ключ: EventID_TaskID_SubtaskID
Value в виде примитивных данных или сериализуемых структур, которые переживут изменения из-за обновлений сущностей
Слайд 30
![Запросы и их задачи Request = намерение RequestTask = как его достичь](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-29.jpg)
Запросы и их задачи
Request = намерение
RequestTask = как его достичь
Слайд 31
![Приложение для организации событий Создаём событие CreateEventRequest Добавляем фото места AddPhotoRequest Добавляем новых участников AddParticipantRequest](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-30.jpg)
Приложение для организации событий
Создаём событие CreateEventRequest
Добавляем фото места AddPhotoRequest
Добавляем новых участников
AddParticipantRequest
Слайд 32
![Приложение для организации событий Request -> RequestTask](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-31.jpg)
Приложение для организации событий
Request -> RequestTask
Слайд 33
![Интерфейс RequestTask public interface IRequestTask { int Id { get;](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-32.jpg)
Интерфейс RequestTask
public interface IRequestTask
{
int Id { get; }
Request Request
{ get; }
ExecutingState State { get; }
Task RunAsync();
void Load(IReadOnlyDictionary data);
IReadOnlyDictionary Save();
}
Слайд 34
![Интерфейс RequestTask public interface IRequestTask { int Id { get;](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-33.jpg)
Интерфейс RequestTask
public interface IRequestTask
{
int Id { get; }
Request Request
{ get; }
ExecutingState State { get; }
Task RunAsync();
void Load(IReadOnlyDictionary data);
IReadOnlyDictionary Save();
}
Слайд 35
![Интерфейс RequestTask public interface IRequestTask { int Id { get;](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-34.jpg)
Интерфейс RequestTask
public interface IRequestTask
{
int Id { get; }
Request Request
{ get; }
ExecutingState State { get; }
Task RunAsync();
void Load(IReadOnlyDictionary data);
IReadOnlyDictionary Save();
}
Слайд 36
![Интерфейс RequestTask public interface IRequestTask { int Id { get;](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-35.jpg)
Интерфейс RequestTask
public interface IRequestTask
{
int Id { get; }
Request Request
{ get; }
ExecutingState State { get; }
Task RunAsync();
void Load(IReadOnlyDictionary data);
IReadOnlyDictionary Save();
}
Слайд 37
![Интерфейс RequestTask public interface IRequestTask { int Id { get;](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-36.jpg)
Интерфейс RequestTask
public interface IRequestTask
{
int Id { get; }
Request Request
{ get; }
ExecutingState State { get; }
Task RunAsync();
void Load(IReadOnlyDictionary data);
IReadOnlyDictionary Save();
}
Слайд 38
![Интерфейс RequestTask public interface IRequestTask { int Id { get;](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-37.jpg)
Интерфейс RequestTask
public interface IRequestTask
{
int Id { get; }
Request Request
{ get; }
ExecutingState State { get; }
Task RunAsync();
void Load(IReadOnlyDictionary data);
IReadOnlyDictionary Save();
}
Слайд 39
![Интерфейс RequestTask public interface IRequestTask { int Id { get;](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-38.jpg)
Интерфейс RequestTask
public interface IRequestTask
{
int Id { get; }
Request Request
{ get; }
ExecutingState State { get; }
Task RunAsync();
void Load(IReadOnlyDictionary data);
IReadOnlyDictionary Save();
}
Слайд 40
![Приложение для организации событий CreateEventRequest CreateEventRequestTask AddPhotoRequest CompressPhotoRequestTask SendPhotoRequestTask AddPhotoToEventRequestTask AddParticipantRequest AddParticipantRequestTask](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-39.jpg)
Приложение для организации событий
CreateEventRequest CreateEventRequestTask
AddPhotoRequest
CompressPhotoRequestTask
SendPhotoRequestTask
AddPhotoToEventRequestTask
AddParticipantRequest AddParticipantRequestTask
Слайд 41
![Очередь](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-40.jpg)
Слайд 42
![Очередь](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-41.jpg)
Слайд 43
![SerialRequestTask public class SerialRequestTask : IRequestTask { private readonly IRequestTask](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-42.jpg)
SerialRequestTask
public class SerialRequestTask : IRequestTask
{
private readonly IRequestTask _wrappedTask;
private readonly
IRequestTask _dependingOnTask;
…
}
Слайд 44
![SerialRequestTask public class SerialRequestTask : IRequestTask { private readonly IRequestTask](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-43.jpg)
SerialRequestTask
public class SerialRequestTask : IRequestTask
{
private readonly IRequestTask _wrappedTask;
private readonly
IRequestTask _dependingOnTask;
…
}
Слайд 45
![SerialRequestTask public class SerialRequestTask : IRequestTask { private readonly IRequestTask](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-44.jpg)
SerialRequestTask
public class SerialRequestTask : IRequestTask
{
private readonly IRequestTask _wrappedTask;
private readonly
IRequestTask _dependingOnTask;
…
}
Слайд 46
![Очередь](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-45.jpg)
Слайд 47
![Очередь](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-46.jpg)
Слайд 48
![Очередь](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-47.jpg)
Слайд 49
![Очередь](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-48.jpg)
Слайд 50
![Очередь](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-49.jpg)
Слайд 51
![Очередь](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-50.jpg)
Слайд 52
![Очередь](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-51.jpg)
Слайд 53
![Очередь](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-52.jpg)
Слайд 54
![Очередь](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-53.jpg)
Слайд 55
![Очередь](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-54.jpg)
Слайд 56
![Очередь](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-55.jpg)
Слайд 57
![Очередь](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-56.jpg)
Слайд 58
![Очередь](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-57.jpg)
Слайд 59
![Очередь](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-58.jpg)
Слайд 60
![Очередь](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-59.jpg)
Слайд 61
![Очередь](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-60.jpg)
Слайд 62
![Очередь](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-61.jpg)
Слайд 63
![Очередь](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-62.jpg)
Слайд 64
![Очередь](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-63.jpg)
Слайд 65
![Очередь](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-64.jpg)
Слайд 66
![Очередь](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-65.jpg)
Слайд 67
![Очередь](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-66.jpg)
Слайд 68
![Очередь](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-67.jpg)
Слайд 69
![Очередь](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-68.jpg)
Слайд 70
![Очередь](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-69.jpg)
Слайд 71
![Очередь](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-70.jpg)
Слайд 72
![Очередь](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-71.jpg)
Слайд 73
![Очередь](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-72.jpg)
Слайд 74
![Очередь](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-73.jpg)
Слайд 75
![Преимущества Удобно разрабатывать Гарантированная доставка Просто визуализировать](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-74.jpg)
Преимущества
Удобно разрабатывать
Гарантированная доставка
Просто визуализировать
Слайд 76
![Недостатки: сложно](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-75.jpg)
Слайд 77
![Недостатки Необходимость синхронизировать очередь Сложный, витиеватый код](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-76.jpg)
Недостатки
Необходимость синхронизировать очередь
Сложный, витиеватый код
Слайд 78
![И ещё пара рецептов](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-77.jpg)
Слайд 79
![Взаимоисключение задач](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-78.jpg)
Слайд 80
![Взаимоисключение задач](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-79.jpg)
Слайд 81
![Взаимоисключение задач public class AddParticipantRequest : Request { public int](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-80.jpg)
Взаимоисключение задач
public class AddParticipantRequest : Request
{
public int EventId { get;
}
public int UserId { get; }
public override RequestConnectedType GetConnectedType(Request anotherRequest) =>
anotherRequest is RemoveParticipantRequest r && r.UserId == UserId
? RequestConnectedType.MutuallyExclusive
: base.GetConnectedType(anotherRequest);
}
Слайд 82
![Взаимоисключение задач public class AddParticipantRequest : Request { public int](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-81.jpg)
Взаимоисключение задач
public class AddParticipantRequest : Request
{
public int EventId { get;
}
public int UserId { get; }
public override RequestConnectedType GetConnectedType(Request anotherRequest) =>
anotherRequest is RemoveParticipantRequest r && r.UserId == UserId
? RequestConnectedType.MutuallyExclusive
: base.GetConnectedType(anotherRequest);
}
Слайд 83
![Взаимоисключение задач public class AddParticipantRequest : Request { public int](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-82.jpg)
Взаимоисключение задач
public class AddParticipantRequest : Request
{
public int EventId { get;
}
public int UserId { get; }
public override RequestConnectedType GetConnectedType(Request anotherRequest) =>
anotherRequest is RemoveParticipantRequest r && r.UserId == UserId
? RequestConnectedType.MutuallyExclusive
: base.GetConnectedType(anotherRequest);
}
Слайд 84
![Взаимоисключение задач public class AddParticipantRequest : Request { public int](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-83.jpg)
Взаимоисключение задач
public class AddParticipantRequest : Request
{
public int EventId { get;
}
public int UserId { get; }
public override RequestConnectedType GetConnectedType(Request anotherRequest) =>
anotherRequest is RemoveParticipantRequest r && r.UserId == UserId
? RequestConnectedType.MutuallyExclusive
: base.GetConnectedType(anotherRequest);
}
Слайд 85
![Взаимоисключение задач public class AddParticipantRequest : Request { public int](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-84.jpg)
Взаимоисключение задач
public class AddParticipantRequest : Request
{
public int EventId { get;
}
public int UserId { get; }
public override RequestConnectedType GetConnectedType(Request anotherRequest) =>
anotherRequest is RemoveParticipantRequest r && r.UserId == UserId
? RequestConnectedType.MutuallyExclusive
: base.GetConnectedType(anotherRequest);
}
Слайд 86
![Взаимоисключение задач](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-85.jpg)
Слайд 87
![Взаимоисключение задач](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-86.jpg)
Слайд 88
![Дедупликация данных](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-87.jpg)
Слайд 89
![Дедупликация данных](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-88.jpg)
Слайд 90
![Дедупликация данных](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-89.jpg)
Слайд 91
![Дедупликация данных](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-90.jpg)
Слайд 92
![Дедупликация данных](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-91.jpg)
Слайд 93
![Дедупликация данных](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-92.jpg)
Слайд 94
![Дедупликация данных RequestId](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-93.jpg)
Дедупликация данных
RequestId
Слайд 95
![Дедупликация данных RequestId RequestId](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-94.jpg)
Дедупликация данных
RequestId
RequestId
Слайд 96
![Итоги Разбиваем задачи на атомарные подзадачи Сохранение и восстановление данных](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/137281/slide-95.jpg)
Итоги
Разбиваем задачи на атомарные подзадачи
Сохранение и восстановление данных и состояния
Связанные задачи
выполняем последовательно
Приоритеты задач
Взаимоисключение задач
Отправка RequestID на сервер и кэширование результата запроса на сервере по этому RequestID