Coverage for src/expo_notifications/tasks/send_messages_task.py: 100%

32 statements  

« prev     ^ index     » next       coverage.py v7.8.0, created at 2025-05-10 02:00 +0000

1from celery import shared_task 

2from django.utils import timezone 

3from exponent_server_sdk import ( 

4 DeviceNotRegisteredError, 

5 PushClient, 

6 PushServerError, 

7 PushTicket, 

8 PushTicketError, 

9) 

10from requests.exceptions import ConnectionError, HTTPError 

11 

12from expo_notifications.conf import settings 

13from expo_notifications.models import Message, Ticket 

14from expo_notifications.tasks import check_receipts 

15from expo_notifications.tasks.session import session 

16 

17 

18@shared_task( 

19 bind=True, 

20 ignore_result=True, 

21 max_retries=settings.sending_task_max_retries, 

22 default_retry_delay=settings.sending_task_retry_delay.total_seconds(), 

23) 

24def send_messages(self, message_pks: list[str]) -> None: 

25 messages = Message.objects.filter(pk__in=message_pks, device__is_active=True) 

26 

27 push_messages = [message.to_push_message() for message in messages] 

28 

29 push_client = PushClient(session=session) 

30 

31 try: 

32 push_tickets: list[PushTicket] = push_client.publish_multiple(push_messages) 

33 except PushServerError: 

34 raise self.retry() 

35 except (ConnectionError, HTTPError): 

36 raise self.retry() 

37 

38 tickets: list[Ticket] = [] 

39 

40 for message, push_ticket in zip(messages, push_tickets): 

41 try: 

42 push_ticket.validate_response() 

43 except DeviceNotRegisteredError: 

44 message.device.is_active = False 

45 message.device.save() 

46 except PushTicketError: 

47 pass 

48 

49 tickets.append( 

50 Ticket( 

51 message=message, 

52 is_success=push_ticket.is_success(), 

53 external_id=push_ticket.id, 

54 error_message=push_ticket.message, 

55 date_received=timezone.now(), 

56 ) 

57 ) 

58 

59 pks_of_success_tickets = [ 

60 ticket.pk for ticket in Ticket.objects.bulk_create(tickets) if ticket.is_success 

61 ] 

62 

63 if pks_of_success_tickets: 

64 check_receipts.apply_async( 

65 kwargs={"ticket_pks": pks_of_success_tickets}, 

66 countdown=settings.receipt_check_delay.total_seconds(), 

67 )