Skip to content

Instantly share code, notes, and snippets.

@Asgavar
Last active November 12, 2018 21:39
Show Gist options
  • Save Asgavar/91e86775e7117afbe1cb3c7ba2d17311 to your computer and use it in GitHub Desktop.
Save Asgavar/91e86775e7117afbe1cb3c7ba2d17311 to your computer and use it in GitHub Desktop.

Notifications

Problem do rozwiązania

W obecnym Systemie Zapisów wiele rzeczy dzieje się w tle i bez ręcznego sprawdzania student nie dowie się na przykład o fakcie zostania 'wciągnietym' do grupy z kolejki oczekujących na zapis na przedmiot. Chcielibyśmy dać użytkownikom możliwość otrzymywania powiadomień o takich zdarzeniach, podzielonych na kategorie.

Architektura

Nasze rozwiązanie można podzielić na kilka głównych części:

  • Realizujący wzorzec projektowy Repository interfejs do zapisywania i odczytywania powiadomień
  • Oparta na systemie Redis implementacja tego interfejsu
  • Widok (django view) pozwalający na przejrzenie powiadomień dotyczących zalogowanego użytkownika
  • Rozszerzenie już istniejącego panelu konfiguracji konta o preferencje otrzymywania powiadomień - przykładowo, chcę dostawać emaile z kategorii X, o kategorii Y nie chcę dostawać niczego
  • Napisany przy użyciu django-rq task zajmujący się faktycznym wysłaniem powiadomień (za pomocą emaila, Web Push Notification bądź dowolnego innego sposobu) asynchronicznie

Data model

Powiadomienie jest wewnętrznie reprezentowane przez klasę Notification, której najciekawszą częścią są dwa atrybuty: description_id oraz description_args. Pierwszy z nich jest niejako wskaźnikiem do szablonu tekstu, który ma zawierać powiadomienie, drugi - słownikiem z parametrami do tego szablonu. Takie podejście pozwoli nam na bezproblemowe przetłumaczenie tych tekstów oraz pozwoli zaoszczędzić miejsce, które powiadomienia zajmują w bazie. Przykładowy szablon:

Zostałeś zapisany na przedmiot {course_name}

gdzie course_name jest właśnie parametrem potrzebnym do wyrenderowania szablonu.

Obiekty tejże klasy przed zapisem będą serializowane (i analogicznie, przed odczytem deserializowane) - pierwszym pomysłem jest JSON, ze względu na swoją prostotę i względną czytelność, jednak w razie jakichkolwiek problemów (na przykład z miejscem w pamięci - każdy obiekt będzie przechowywał informacje o nazwach swoich kluczy, co w tym wypadku raczej nie będzie konieczne, jako że klucze te powtarzają się w każdym powiadomieniu) zmiana go na dowolny inny format będzie trywialna.

Po stronie Redisa natomiast oprzemy się na udostępnianej przez niego strukturze Set, która pozwala m.in. na uzyskanie informacji o liczebności zbioru (powiadomień) w O(1). Każdy użytkownik będzie posiadał przypisane do siebie dwa takie Sety, przykładowo, dla studenta z ID = 1234: notifications_unsent_1234 oraz notifications_sent_1234. Pierwszy z nich zawiera powiadomienia, o których informacje nie zostały jeszcze wysłane - przy zapisie nowego powiadomienia trafia ono właśnie tutaj. Natomiast drugi z nich zawiera powiadomienia, o których użytkownik został już poinformowany - jedną z czynności, które będzie wykonywał task zajmujący się rozsyłaniem tych informacji będzie przekładanie ich z jednego zbioru do drugiego.

Przykładowy flow

TODO

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment