Отправить всё! Поддержка офлайна в мобильном приложении. Рецепт от Solo
Цель
О чём пойдёт речь
Чего не будет
Интро
Отправка созданных пользователем данных
Отправка созданных пользователем данных
Отправка созданных пользователем данных
Когда узнаешь, что данные пропали
Отправка созданных пользователем данных
Отправка созданных пользователем данных
Отправка созданных пользователем данных
Приложение для организации событий
Приложение для организации событий
Задачи
Схема задач
Схема задач
Схема задач
Схема задач
Схема задач
Схема задач
Схема задач
Схема задач
Схема задач
Схема задач
Схема задач
Схема задач
Схема задач
Отправка созданных пользователем данных
Запросы и их задачи
Приложение для организации событий
Приложение для организации событий
Интерфейс RequestTask
Интерфейс RequestTask
Интерфейс RequestTask
Интерфейс RequestTask
Интерфейс RequestTask
Интерфейс RequestTask
Интерфейс RequestTask
Приложение для организации событий
Очередь
Очередь
SerialRequestTask
SerialRequestTask
SerialRequestTask
Очередь
Очередь
Очередь
Очередь
Очередь
Очередь
Очередь
Очередь
Очередь
Очередь
Очередь
Очередь
Очередь
Очередь
Очередь
Очередь
Очередь
Очередь
Очередь
Очередь
Очередь
Очередь
Очередь
Очередь
Очередь
Очередь
Очередь
Очередь
Очередь
Преимущества
Недостатки: сложно
Недостатки
И ещё пара рецептов
Взаимоисключение задач
Взаимоисключение задач
Взаимоисключение задач
Взаимоисключение задач
Взаимоисключение задач
Взаимоисключение задач
Взаимоисключение задач
Взаимоисключение задач
Взаимоисключение задач
Дедупликация данных
Дедупликация данных
Дедупликация данных
Дедупликация данных
Дедупликация данных
Дедупликация данных
Дедупликация данных
Дедупликация данных
Итоги
Спасибо
2.37M
Категория: ПрограммированиеПрограммирование

Поддержка офлайна в мобильном приложении

1. Отправить всё! Поддержка офлайна в мобильном приложении. Рецепт от Solo

1
Отправить всё!
Поддержка офлайна в мобильном
приложении. Рецепт от Solo
Владимир Абакумов

2. Цель

2
Цель
Поделиться подходом к неблокирующей отправке созданных
пользователем данных на сервер

3. О чём пойдёт речь

3
О чём пойдёт речь
Как «хорошо» отправлять данные на сервер:
• концепция
• варианты реализации
• и ещё пара рецептов

4. Чего не будет

4
Чего не будет
• Транзакционность

5. Интро

5
Интро
• Владимир Абакумов, TeamLead ОМР
• DIRECTUM и DirectumRX
• DIRECTUM Solo и Jazz

6. Отправка созданных пользователем данных

6
Отправка созданных пользователем данных
• Блокируем работу

7. Отправка созданных пользователем данных

7
Отправка созданных пользователем данных
• Блокируем работу
• Просто и надежно
• Ответственность на пользователе
• Бесяче (╯ ° □ °) ╯ (┻━┻)

8. Отправка созданных пользователем данных

8
Отправка созданных пользователем данных
• Не блокируем работу

9. Когда узнаешь, что данные пропали

9
Когда узнаешь, что данные пропали

10. Отправка созданных пользователем данных

10
Отправка созданных пользователем данных
• Не блокируем работу
• Не понятен статус

11. Отправка созданных пользователем данных

11
Отправка созданных пользователем данных
• Не блокируем работу
• Не понятен статус
• Можно потерять данные

12. Отправка созданных пользователем данных

12
Отправка созданных пользователем данных
• Не блокируем работу
• Не теряем данные

13. Приложение для организации событий

13
Приложение для организации событий

14. Приложение для организации событий

14
Приложение для организации событий
• Создаём событие, указывая реквизиты, участников
• Добавляем фото места
• Добавляем новых участников

15. Задачи

15
Задачи
• Создать событие
• Добавить фото:
• Обработать фото (сжатие, фильтры);
• Отправить файл на сервер и получить URL;
• Прикрепить к событию.
• Добавить участников

16. Схема задач

16
Схема задач
Создание
события
Создать
событие
Обработать
фото
Добавить
фото
Отправить
фото
Добавить
участников
Добавить к
событию

17. Схема задач

17
Схема задач
Создание
события
Создать
событие
Обработать
фото
Добавить
фото
Отправить
фото
Добавить
участников
Добавить к
событию

18. Схема задач

18
Схема задач
Создание
события
Создать
событие
Обработать
фото
Добавить
фото
Отправить
фото
Добавить
участников
Добавить к
событию

19. Схема задач

19
Схема задач
Создание
события
Создать
событие
Обработать
фото
Добавить
фото
Отправить
фото
Добавить
участников
Добавить к
событию

20. Схема задач

20
Схема задач
Создание
события
Создать
событие
Обработать
фото
Добавить
фото
Отправить
фото
Добавить
участников
Добавить к
событию

21. Схема задач

21
Схема задач
Создание
события
Создать
событие
Обработать
фото
Добавить
фото
Отправить
фото
Добавить
участников
Добавить к
событию

22. Схема задач

22
Схема задач
Создание
события
Создать
событие
Обработать
фото
Добавить
фото
Отправить
фото
Добавить
участников
Добавить к
событию

23. Схема задач

23
Схема задач

24. Схема задач

24
Схема задач

25. Схема задач

25
Схема задач
Создание
события
Создать
событие
Обработать
фото
Добавить
фото
Отправить
фото
Добавить
участников
Добавить к
событию

26. Схема задач

26
Схема задач
Создание
события
Создать
событие
Обработать
фото
Добавить
фото
Отправить
фото
Добавить
участников
Добавить к
событию

27. Схема задач

27
Схема задач
Создание
события
Создать
событие
Обработать
фото
Добавить
фото
Отправить
фото
Добавить
участников
Добавить к
событию

28. Схема задач

28
Схема задач
Создание
события
Создать
событие
Обработать
фото
Добавить
фото
Отправить
фото
Добавить
участников
Добавить к
событию

29. Отправка созданных пользователем данных

29
Отправка созданных пользователем данных
• Разбиваем задачи на атомарные подзадачи
• Сохранение данных и состояния задач
• Семантически значимый ключ: EventID_TaskID_SubtaskID
• Value в виде примитивных данных или сериализуемых структур, которые
переживут изменения из-за обновлений сущностей

30. Запросы и их задачи

30
Запросы и их задачи
• Request = намерение
• RequestTask = как его достичь

31. Приложение для организации событий

31
Приложение для организации событий
• Создаём событие
• Добавляем фото места
• Добавляем новых участников
CreateEventRequest
AddPhotoRequest
AddParticipantRequest

32. Приложение для организации событий

32
Приложение для организации событий
• Request -> RequestTask

33. Интерфейс RequestTask

33
Интерфейс RequestTask
public interface IRequestTask
{
int Id { get; }
Request Request { get; }
ExecutingState State { get; }
Task RunAsync();
void Load(IReadOnlyDictionary<string, object> data);
IReadOnlyDictionary<string, object> Save();
}

34. Интерфейс RequestTask

34
Интерфейс RequestTask
public interface IRequestTask
{
int Id { get; }
Request Request { get; }
ExecutingState State { get; }
Task RunAsync();
void Load(IReadOnlyDictionary<string, object> data);
IReadOnlyDictionary<string, object> Save();
}

35. Интерфейс RequestTask

35
Интерфейс RequestTask
public interface IRequestTask
{
int Id { get; }
Request Request { get; }
ExecutingState State { get; }
Task RunAsync();
void Load(IReadOnlyDictionary<string, object> data);
IReadOnlyDictionary<string, object> Save();
}

36. Интерфейс RequestTask

36
Интерфейс RequestTask
public interface IRequestTask
{
int Id { get; }
Request Request { get; }
ExecutingState State { get; }
Task RunAsync();
void Load(IReadOnlyDictionary<string, object> data);
IReadOnlyDictionary<string, object> Save();
}

37. Интерфейс RequestTask

37
Интерфейс RequestTask
public interface IRequestTask
{
int Id { get; }
Request Request { get; }
ExecutingState State { get; }
Task RunAsync();
void Load(IReadOnlyDictionary<string, object> data);
IReadOnlyDictionary<string, object> Save();
}

38. Интерфейс RequestTask

38
Интерфейс RequestTask
public interface IRequestTask
{
int Id { get; }
Request Request { get; }
ExecutingState State { get; }
Task RunAsync();
void Load(IReadOnlyDictionary<string, object> data);
IReadOnlyDictionary<string, object> Save();
}

39. Интерфейс RequestTask

39
Интерфейс RequestTask
public interface IRequestTask
{
int Id { get; }
Request Request { get; }
ExecutingState State { get; }
Task RunAsync();
void Load(IReadOnlyDictionary<string, object> data);
IReadOnlyDictionary<string, object> Save();
}

40. Приложение для организации событий

40
Приложение для организации событий
• CreateEventRequest
CreateEventRequestTask
• AddPhotoRequest
CompressPhotoRequestTask
SendPhotoRequestTask
AddPhotoToEventRequestTask
• AddParticipantRequest AddParticipantRequestTask

41. Очередь

41
Очередь
CreateEvent
CompressPhoto
SendPhoto
AddPhotoToEvent
AddParticipants

42. Очередь

42
Очередь
CreateEvent
CompressPhoto
Executor 1
SendPhoto
AddPhotoToEvent
AddParticipants
Executor 2

43. SerialRequestTask

43
SerialRequestTask
public class SerialRequestTask : IRequestTask
{
private readonly IRequestTask _wrappedTask;
private readonly IRequestTask _dependingOnTask;

}

44. SerialRequestTask

44
SerialRequestTask
public class SerialRequestTask : IRequestTask
{
private readonly IRequestTask _wrappedTask;
private readonly IRequestTask _dependingOnTask;

}

45. SerialRequestTask

45
SerialRequestTask
public class SerialRequestTask : IRequestTask
{
private readonly IRequestTask _wrappedTask;
private readonly IRequestTask _dependingOnTask;

}

46. Очередь

CreateEvent
Scheduler
CompressPhoto
AddParticipants
SendPhoto
46
Executor
1
Executor 2
AddPhotoToEvent

47. Очередь

CreateEvent
Scheduler
CompressPhoto
Executor 1
AddParticipants
SendPhoto
47
Executor
1
Executor 2
AddPhotoToEvent

48. Очередь

CreateEvent
Scheduler
CompressPhoto
Executor 1
AddParticipants
SendPhoto
48
Executor
1
Executor 2
AddPhotoToEvent

49. Очередь

CreateEvent
Scheduler
CompressPhoto
Executor 1
AddParticipants
SendPhoto
49
Executor
1
Executor 2
AddPhotoToEvent

50. Очередь

CreateEvent
Scheduler
CompressPhoto
Executor 1
AddParticipants
SendPhoto
50
Executor
1
Executor 2
AddPhotoToEvent

51. Очередь

51
Очередь
CreateEvent
Scheduler
CompressPhoto
Executor 1
AddParticipants
Executor 2
SendPhoto
AddPhotoToEvent

52. Очередь

52
Очередь
CreateEvent
Scheduler
CompressPhoto
Executor 1
AddParticipants
Executor 2
SendPhoto
AddPhotoToEvent

53. Очередь

53
Очередь
CreateEvent
Scheduler
CompressPhoto
SendPhoto
Executor 1
AddParticipants
Executor 2
AddPhotoToEvent

54. Очередь

54
Очередь
CreateEvent
Scheduler
CompressPhoto
SendPhoto
Executor 1
AddParticipants
Executor 2
AddPhotoToEvent

55. Очередь

55
Очередь
Scheduler
Executor 2
CreateEvent
CompressPhoto
SendPhoto
Executor 1
AddParticipants
AddPhotoToEvent

56. Очередь

56
Очередь
Scheduler
Executor 2
CreateEvent
CompressPhoto
SendPhoto
AddPhotoToEvent
Executor 1
AddParticipants

57. Очередь

57
Очередь
Scheduler
Executor 2
CreateEvent
CompressPhoto
SendPhoto
AddPhotoToEvent
Executor 1
AddParticipants

58. Очередь

58
Очередь
Scheduler
Executor 1
Executor 2
CreateEvent
CompressPhoto
AddParticipants
SendPhoto
AddPhotoToEvent

59. Очередь

[0] CreateEvent
Scheduler
[ 1] CompressPhoto
[0] AddParticipants
[1] SendPhoto
59
Executor
1
Executor 2
[1] AddPhotoToEvent

60. Очередь

60
Очередь
[0] CreateEvent
Scheduler
Executor 2
[ 1] CompressPhoto
Executor 1
[0] AddParticipants
[1] SendPhoto
[1] AddPhotoToEvent

61. Очередь

61
Очередь
[0] CreateEvent
Scheduler
Executor 2
[ 1] CompressPhoto
Executor 1
[0] AddParticipants
[1] SendPhoto
[1] AddPhotoToEvent

62. Очередь

62
Очередь
[0] CreateEvent
Scheduler
Executor 2
[ 1] CompressPhoto
[0] AddParticipants
Executor 1
[1] SendPhoto
[1] AddPhotoToEvent

63. Очередь

63
Очередь
[0] CreateEvent
Scheduler
Executor 2
[ 1] CompressPhoto
[0] AddParticipants
Executor 1
[1] SendPhoto
[1] AddPhotoToEvent

64. Очередь

64
Очередь
[0] CreateEvent
Scheduler
[ 1] CompressPhoto
Executor 2
[0] AddParticipants
Executor 1
[1] SendPhoto
[1] AddPhotoToEvent

65. Очередь

65
Очередь
[0] CreateEvent
Scheduler
[ 1] CompressPhoto
[1] SendPhoto
Executor 2
[0] AddParticipants
Executor 1
[0] AddParticipants
[1] AddPhotoToEvent

66. Очередь

66
Очередь
[0] CreateEvent
Scheduler
[ 1] CompressPhoto
[1] SendPhoto
Executor 2
[0] AddParticipants
Executor 1
[0] AddParticipants
[1] AddPhotoToEvent

67. Очередь

67
Очередь
[0] CreateEvent
Scheduler
[ 1] CompressPhoto
[1] SendPhoto
[0] AddParticipants
[0] AddParticipants
Executor 1
Executor 2
[1] AddPhotoToEvent

68. Очередь

68
Очередь
[0] CreateEvent
Scheduler
[ 1] CompressPhoto
[1] SendPhoto
[0] AddParticipants
[0] AddParticipants
Executor 1
Executor 2
[1] AddPhotoToEvent

69. Очередь

69
Очередь
[0] CreateEvent
Scheduler
[ 1] CompressPhoto
[1] SendPhoto
[0] AddParticipants
[0] AddParticipants
Executor 1
Executor 2
[1] AddPhotoToEvent

70. Очередь

70
Очередь
[0] CreateEvent
Scheduler
[ 1] CompressPhoto
[1] SendPhoto
Executor 1
[0] AddParticipants
[0] AddParticipants
Executor 2
[1] AddPhotoToEvent

71. Очередь

71
Очередь
[0] CreateEvent
Scheduler
[ 1] CompressPhoto
[1] SendPhoto
Executor 1
[0] AddParticipants
[0] AddParticipants
Executor 2
[1] AddPhotoToEvent

72. Очередь

72
Очередь
Scheduler
Executor 2
[0] CreateEvent
[ 1] CompressPhoto
[1] SendPhoto
[1] AddPhotoToEvent
Executor 1
[0] AddParticipants
[0] AddParticipants

73. Очередь

73
Очередь
Scheduler
Executor 2
[0] CreateEvent
[ 1] CompressPhoto
[1] SendPhoto
[1] AddPhotoToEvent
Executor 1
[0] AddParticipants
[0] AddParticipants

74. Очередь

74
Очередь
Scheduler
Executor 1
Executor 2
[0] CreateEvent
[ 1] CompressPhoto
[0] AddParticipants
[1] SendPhoto
[0] AddParticipants
[1] AddPhotoToEvent

75. Преимущества

75
Преимущества
• Удобно разрабатывать
• Гарантированная доставка
• Просто визуализировать

76. Недостатки: сложно

76
Недостатки: сложно

77. Недостатки

77
Недостатки
• Необходимость синхронизировать очередь
• Сложный, витиеватый код

78. И ещё пара рецептов

78
И ещё пара рецептов

79. Взаимоисключение задач

79
Взаимоисключение задач
AddParticipant

80. Взаимоисключение задач

80
Взаимоисключение задач
AddParticipant
RemoveParticipant

81. Взаимоисключение задач

81
Взаимоисключение задач
public class AddParticipantRequest : Request
{
public int EventId { get; }
public int UserId { get; }
AddParticipant
public override RequestConnectedType GetConnectedType(Request
anotherRequest) =>
anotherRequest is RemoveParticipantRequest r && r.UserId == UserId
? RequestConnectedType.MutuallyExclusive
: base.GetConnectedType(anotherRequest);
}
RemoveParticipant

82. Взаимоисключение задач

82
Взаимоисключение задач
public class AddParticipantRequest : Request
{
public int EventId { get; }
public int UserId { get; }
AddParticipant
public override RequestConnectedType GetConnectedType(Request
anotherRequest) =>
anotherRequest is RemoveParticipantRequest r && r.UserId == UserId
? RequestConnectedType.MutuallyExclusive
: base.GetConnectedType(anotherRequest);
}
RemoveParticipant

83. Взаимоисключение задач

83
Взаимоисключение задач
public class AddParticipantRequest : Request
{
public int EventId { get; }
public int UserId { get; }
AddParticipant
public override RequestConnectedType GetConnectedType(Request
anotherRequest) =>
anotherRequest is RemoveParticipantRequest r && r.UserId == UserId
? RequestConnectedType.MutuallyExclusive
: base.GetConnectedType(anotherRequest);
}
RemoveParticipant

84. Взаимоисключение задач

84
Взаимоисключение задач
public class AddParticipantRequest : Request
{
public int EventId { get; }
public int UserId { get; }
AddParticipant
public override RequestConnectedType GetConnectedType(Request
anotherRequest) =>
anotherRequest is RemoveParticipantRequest r && r.UserId == UserId
? RequestConnectedType.MutuallyExclusive
: base.GetConnectedType(anotherRequest);
}
RemoveParticipant

85. Взаимоисключение задач

85
Взаимоисключение задач
public class AddParticipantRequest : Request
{
public int EventId { get; }
public int UserId { get; }
AddParticipant
public override RequestConnectedType GetConnectedType(Request
anotherRequest) =>
anotherRequest is RemoveParticipantRequest r && r.UserId == UserId
? RequestConnectedType.MutuallyExclusive
: base.GetConnectedType(anotherRequest);
}
RemoveParticipant

86. Взаимоисключение задач

86
Взаимоисключение задач
AddParticipant
RemoveParticipant

87. Взаимоисключение задач

87
Взаимоисключение задач

88. Дедупликация данных

88
Дедупликация данных
Создание
события
Ошибка
сети
Создание
события

89. Дедупликация данных

89
Дедупликация данных
Создание
события
Создаю
Ошибка
сети
Создал
Создание
события
Создал

90. Дедупликация данных

90
Дедупликация данных
Создание
события
Создаю
Ошибка
сети
Создал
Создание
события
Создал

91. Дедупликация данных

91
Дедупликация данных
Создание
события
Создаю
Ошибка
сети
Создал
Создание
события
Создал

92. Дедупликация данных

92
Дедупликация данных
Создание
события
Создаю
Ошибка
сети
Создал
Создание
события
Создал

93. Дедупликация данных

93
Дедупликация данных
Создание
события
Создаю
Ошибка
сети
Создал
Создание
события
Создаю

94. Дедупликация данных

94
Дедупликация данных
Создание
события
RequestId
Создаю
Ошибка
сети
Создал
Создание
события
Да создал
уже!

95. Дедупликация данных

95
Дедупликация данных
Создание
события
RequestId
Ошибка
сети
Создание
события
Создаю
Создал
RequestId
Да создал
уже!

96. Итоги

96
Итоги
• Разбиваем задачи на атомарные подзадачи
• Сохранение и восстановление данных и состояния
• Связанные задачи выполняем последовательно
• Приоритеты задач
• Взаимоисключение задач
• Отправка RequestID на сервер и кэширование результата запроса
на сервере по этому RequestID

97. Спасибо

97
Спасибо
English     Русский Правила