aa-killtracker 0.16.0__py3-none-any.whl → 0.18.0a2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,36 +2,35 @@
2
2
 
3
3
  # pylint: disable = redefined-builtin
4
4
 
5
+ import datetime as dt
5
6
  import json
6
7
  from copy import deepcopy
7
8
  from dataclasses import asdict, dataclass
8
- from datetime import datetime
9
9
  from http import HTTPStatus
10
+ from time import sleep
10
11
  from typing import List, Optional, Set
11
12
  from urllib.parse import quote_plus
12
13
 
13
14
  import requests
14
15
  from dacite import DaciteError, from_dict
15
- from redis.exceptions import LockError
16
16
  from simplejson.errors import JSONDecodeError
17
17
 
18
- from django.conf import settings
19
18
  from django.core.cache import cache
20
19
  from django.core.exceptions import ImproperlyConfigured
21
20
  from django.utils.dateparse import parse_datetime
21
+ from django.utils.timezone import now
22
22
  from eveuniverse.models import EveType
23
23
 
24
24
  from allianceauth.services.hooks import get_extension_logger
25
- from app_utils.allianceauth import get_redis_client
26
25
  from app_utils.json import JSONDateTimeDecoder, JSONDateTimeEncoder
27
26
  from app_utils.logging import LoggerAddTag
28
27
 
29
28
  from killtracker import USER_AGENT_TEXT, __title__
30
29
  from killtracker.app_settings import (
31
30
  KILLTRACKER_QUEUE_ID,
32
- KILLTRACKER_REDISQ_LOCK_TIMEOUT,
33
31
  KILLTRACKER_REDISQ_TTW,
34
32
  KILLTRACKER_STORAGE_KILLMAILS_LIFETIME,
33
+ KILLTRACKER_ZKB_REQUEST_DELAY,
35
34
  )
36
35
  from killtracker.exceptions import KillmailDoesNotExist
37
36
  from killtracker.providers import esi
@@ -42,6 +41,7 @@ ZKB_REDISQ_URL = "https://zkillredisq.stream/listen.php"
42
41
  ZKB_API_URL = "https://zkillboard.com/api/"
43
42
  ZKB_KILLMAIL_BASEURL = "https://zkillboard.com/kill/"
44
43
  REQUESTS_TIMEOUT = (5, 30)
44
+ DEFAULT_429_TIMEOUT = 10
45
45
 
46
46
  MAIN_MINIMUM_COUNT = 2
47
47
  MAIN_MINIMUM_SHARE = 0.25
@@ -49,6 +49,14 @@ MAIN_MINIMUM_SHARE = 0.25
49
49
  # TODO: Factor out logic for accessing the API to another module
50
50
 
51
51
 
52
+ class ZKBTooManyRequestsError(Exception):
53
+ """ZKB RedisQ API has returned 429 Too Many Requests HTTP status code."""
54
+
55
+ def __init__(self, retry_at: dt.datetime, is_original: bool = True):
56
+ self.retry_at = retry_at
57
+ self.is_original = is_original
58
+
59
+
52
60
  @dataclass
53
61
  class _KillmailBase:
54
62
  """Base class for all Killmail."""
@@ -160,7 +168,7 @@ class Killmail(_KillmailBase):
160
168
  _STORAGE_BASE_KEY = "killtracker_storage_killmail_"
161
169
 
162
170
  id: int
163
- time: datetime
171
+ time: dt.datetime
164
172
  victim: KillmailVictim
165
173
  attackers: List[KillmailAttacker]
166
174
  position: KillmailPosition
@@ -363,7 +371,10 @@ class Killmail(_KillmailBase):
363
371
 
364
372
  @classmethod
365
373
  def get(cls, id: int) -> "Killmail":
366
- """Fetch a killmail from temporary storage."""
374
+ """Fetch a killmail from temporary storage.
375
+
376
+ Raises KillmailDoesNotExist if killmail does not exit.
377
+ """
367
378
  data = cache.get(key=cls._storage_key(id))
368
379
  if not data:
369
380
  raise KillmailDoesNotExist(
@@ -391,9 +402,14 @@ class Killmail(_KillmailBase):
391
402
 
392
403
  @classmethod
393
404
  def create_from_zkb_redisq(cls) -> Optional["Killmail"]:
394
- """Fetches and returns a killmail from ZKB.
405
+ """Fetches and returns a killmail from ZKB REDISQ API.
406
+
407
+ Will automatically wait for a free rate limit slot if needed.
408
+ Will re-raise TooManyRequests if a recent 429 timeout is not yet expired.
395
409
 
396
- Returns None if no killmail is received.
410
+ This method is not thread safe.
411
+
412
+ Returns None if no killmail was received.
397
413
  """
398
414
  if not KILLTRACKER_QUEUE_ID:
399
415
  raise ImproperlyConfigured(
@@ -403,51 +419,85 @@ class Killmail(_KillmailBase):
403
419
  if "," in KILLTRACKER_QUEUE_ID:
404
420
  raise ImproperlyConfigured("A queue ID must not contains commas.")
405
421
 
406
- redis = get_redis_client()
407
- params = {
408
- "queueID": quote_plus(KILLTRACKER_QUEUE_ID),
409
- "ttw": KILLTRACKER_REDISQ_TTW,
410
- }
411
- try:
412
- logger.info("Trying to fetch killmail from ZKB RedisQ...")
413
- with redis.lock(
414
- cls.lock_key(), blocking_timeout=KILLTRACKER_REDISQ_LOCK_TIMEOUT
415
- ):
416
- response = requests.get(
417
- ZKB_REDISQ_URL,
418
- params=params,
419
- timeout=REQUESTS_TIMEOUT,
420
- headers={"User-Agent": USER_AGENT_TEXT},
421
- )
422
- except LockError:
422
+ key_retry_at = "killtracker-retry-at"
423
+ if (v := cache.get(key_retry_at)) is not None:
424
+ try:
425
+ retry_at = dt.datetime.fromisoformat(v)
426
+ except (TypeError, ValueError):
427
+ cache.delete(key_retry_at)
428
+ logger.warning("unable to parse timestamp of retry at")
429
+ return None
430
+
431
+ if retry_at > now():
432
+ raise ZKBTooManyRequestsError(retry_at=retry_at, is_original=False)
433
+
434
+ key_last_request = "killtracker-last-request"
435
+ if (v := cache.get(key_last_request)) is not None:
436
+ try:
437
+ last_request = dt.datetime.fromisoformat(v)
438
+ except (TypeError, ValueError):
439
+ cache.delete(key_last_request)
440
+ logger.warning("unable to parse timestamp of last request")
441
+ last_request = now()
442
+
443
+ next_slot = last_request + dt.timedelta(
444
+ milliseconds=KILLTRACKER_ZKB_REQUEST_DELAY
445
+ )
446
+ seconds = (next_slot - now()).total_seconds()
447
+ if seconds > 0:
448
+ logger.debug("Waiting %f seconds to for next free slot", seconds)
449
+ sleep(seconds)
450
+
451
+ response = requests.get(
452
+ ZKB_REDISQ_URL,
453
+ params={
454
+ "queueID": quote_plus(KILLTRACKER_QUEUE_ID),
455
+ "ttw": KILLTRACKER_REDISQ_TTW,
456
+ },
457
+ timeout=REQUESTS_TIMEOUT,
458
+ headers={"User-Agent": USER_AGENT_TEXT},
459
+ )
460
+ cache.set(key_last_request, dt.datetime.isoformat(now()), timeout=30)
461
+ logger.debug(
462
+ "Response from ZKB API: %d %s %s",
463
+ response.status_code,
464
+ response.headers,
465
+ response.text,
466
+ )
467
+
468
+ if not response.ok:
423
469
  logger.warning(
424
- "Failed to acquire lock for atomic access to RedisQ.",
425
- exc_info=settings.DEBUG, # provide details in DEBUG mode
470
+ "ZKB API returned error: %d %s", response.status_code, response.text
426
471
  )
427
- return None
472
+ if response.status_code == HTTPStatus.TOO_MANY_REQUESTS:
473
+ try:
474
+ retry_after = int(response.headers["Retry-After"])
475
+ except KeyError:
476
+ retry_after = DEFAULT_429_TIMEOUT
477
+ retry_at = now() + dt.timedelta(seconds=retry_after)
478
+ cache.set(key_retry_at, retry_at.isoformat(), timeout=retry_after + 60)
479
+ raise ZKBTooManyRequestsError(retry_at=retry_at, is_original=True)
428
480
 
429
- if response.status_code == HTTPStatus.TOO_MANY_REQUESTS:
430
- logger.error("429 Client Error: Too many requests: %s", response.text)
431
481
  return None
432
482
 
433
- response.raise_for_status()
434
-
435
483
  try:
436
484
  data = response.json()
437
485
  except JSONDecodeError:
438
- logger.error("Error from ZKB API:\n%s", response.text)
486
+ logger.error("Error parsing ZKB API response:\n%s", response.text)
439
487
  return None
440
488
 
441
- if data:
442
- logger.debug("data:\n%s", data)
489
+ if not data or "package" not in data or not data["package"]:
490
+ logger.info("ZKB did not return a killmail")
491
+ return None
443
492
 
444
- if data and "package" in data and data["package"]:
445
- logger.info("Received a killmail from ZKB RedisQ")
446
- package_data = data["package"]
447
- return cls._create_from_dict(package_data)
493
+ package_data = data["package"]
494
+ km = cls._create_from_dict(package_data)
495
+ if km is not None:
496
+ logger.info("ZKB returned killmail %d", km.id)
497
+ else:
498
+ logger.info("Failed to parse killmail from ZKB")
448
499
 
449
- logger.debug("Did not received a killmail from ZKB RedisQ")
450
- return None
500
+ return km
451
501
 
452
502
  @classmethod
453
503
  def create_from_zkb_api(cls, killmail_id: int) -> Optional["Killmail"]:
@@ -601,20 +651,3 @@ class Killmail(_KillmailBase):
601
651
  params[prop] = zkb_data[prop]
602
652
 
603
653
  return KillmailZkb(**params)
604
-
605
- @staticmethod
606
- def lock_key() -> str:
607
- """Key used for lock operation on Redis."""
608
- return f"{__title__.upper()}_REDISQ_LOCK"
609
-
610
- @classmethod
611
- def reset_lock_key(cls):
612
- """Delete lock key if it exists.
613
-
614
- It can happen that a lock key is not cleaned up
615
- and then prevents this class from ever acquiring a lock again.
616
- To prevent this we are deleting the lock key at system start.
617
- """
618
- redis = get_redis_client()
619
- if redis.delete(cls.lock_key()) > 0:
620
- logger.warning("A stuck lock key was cleared.")
@@ -0,0 +1,47 @@
1
+ """Module worker_shutdown allows tasks to find out
2
+ whether their worker is currently shutting down.
3
+
4
+ This enables long running tasks to abort early,
5
+ which helps to speed up a warm worker shutdown.
6
+ """
7
+
8
+ from celery import Task
9
+
10
+ from django.core.cache import cache
11
+
12
+ from allianceauth.services.hooks import get_extension_logger
13
+ from app_utils.logging import LoggerAddTag
14
+
15
+ from killtracker import __title__
16
+
17
+ _TIMEOUT_SECONDS = 120
18
+
19
+ logger = LoggerAddTag(get_extension_logger(__name__), __title__)
20
+
21
+
22
+ def reset(hostname: str) -> None:
23
+ """Resets the shutting down state for a worker."""
24
+ cache.delete(_make_key(hostname))
25
+
26
+
27
+ def set(hostname: str) -> None:
28
+ """Sets a worker into the shutting down state."""
29
+ cache.set(_make_key(hostname), "shutting down", timeout=_TIMEOUT_SECONDS)
30
+
31
+
32
+ def is_shutting_down(task: Task) -> bool:
33
+ """Reports whether the worker of a celery task is currently shutting down."""
34
+ try:
35
+ hostname = str(task.request.hostname)
36
+ except (AttributeError, TypeError, ValueError):
37
+ logger.warning("Failed to retrieve hostname: %s", task)
38
+ return False
39
+
40
+ if cache.get(_make_key(hostname)) is None:
41
+ return False
42
+
43
+ return True
44
+
45
+
46
+ def _make_key(hostname: str) -> str:
47
+ return f"killtracker-worker-shutting-down-{hostname}"
killtracker/forms.py CHANGED
@@ -7,7 +7,7 @@ from django.core.exceptions import ValidationError
7
7
  from django.forms.widgets import TextInput
8
8
  from django.utils.translation import gettext_lazy as _
9
9
 
10
- from .models import Tracker
10
+ from killtracker.models import Tracker
11
11
 
12
12
 
13
13
  def field_nice_display(name: str) -> str:
killtracker/managers.py CHANGED
@@ -13,9 +13,9 @@ from allianceauth.services.hooks import get_extension_logger
13
13
  from app_utils.caching import ObjectCacheMixin
14
14
  from app_utils.logging import LoggerAddTag
15
15
 
16
- from . import __title__
17
- from .app_settings import KILLTRACKER_PURGE_KILLMAILS_AFTER_DAYS
18
- from .core.killmails import Killmail, _KillmailCharacter
16
+ from killtracker import __title__
17
+ from killtracker.app_settings import KILLTRACKER_PURGE_KILLMAILS_AFTER_DAYS
18
+ from killtracker.core.killmails import Killmail, _KillmailCharacter
19
19
 
20
20
  logger = LoggerAddTag(get_extension_logger(__name__), __title__)
21
21
 
@@ -28,6 +28,7 @@ from app_utils.logging import LoggerAddTag
28
28
  from killtracker import __title__
29
29
  from killtracker.app_settings import KILLTRACKER_KILLMAIL_MAX_AGE_FOR_TRACKER
30
30
  from killtracker.constants import EveCategoryId, EveGroupId
31
+ from killtracker.core.discord_messages import DiscordMessage
31
32
  from killtracker.core.killmails import Killmail
32
33
  from killtracker.managers import TrackerManager
33
34
 
@@ -881,12 +882,9 @@ class Tracker(models.Model):
881
882
  def generate_killmail_message(
882
883
  self, killmail: Killmail, intro_text: Optional[str] = None
883
884
  ) -> int:
884
- """generate a message from given killmail and enqueue for later sending
885
+ """Generate a message from given killmail and enqueue for later sending.
885
886
 
886
- returns new queue size
887
+ Returns the new queue size.
887
888
  """
888
- from killtracker.core import discord_messages
889
-
890
- content = discord_messages.create_content(self, intro_text)
891
- embed = discord_messages.create_embed(self, killmail)
892
- return self.webhook.enqueue_message(content=content, embeds=[embed])
889
+ message = DiscordMessage.from_killmail(self, killmail, intro_text)
890
+ return self.webhook.enqueue_message(message)
@@ -1,7 +1,6 @@
1
1
  """Webhooks models for killtracker."""
2
2
 
3
- import json
4
- from typing import List, Optional
3
+ from typing import Optional
5
4
 
6
5
  import dhooks_lite
7
6
  from simple_mq import SimpleMQ
@@ -12,12 +11,12 @@ from django.utils.translation import gettext_lazy as _
12
11
 
13
12
  from allianceauth.services.hooks import get_extension_logger
14
13
  from app_utils.allianceauth import get_redis_client
15
- from app_utils.json import JSONDateTimeDecoder, JSONDateTimeEncoder
16
14
  from app_utils.logging import LoggerAddTag
17
15
  from app_utils.urls import static_file_absolute_url
18
16
 
19
17
  from killtracker import APP_NAME, HOMEPAGE_URL, __title__, __version__
20
18
  from killtracker.app_settings import KILLTRACKER_WEBHOOK_SET_AVATAR
19
+ from killtracker.core.discord_messages import DiscordMessage
21
20
  from killtracker.exceptions import WebhookTooManyRequests
22
21
  from killtracker.managers import WebhookManager
23
22
 
@@ -63,8 +62,8 @@ class Webhook(models.Model):
63
62
 
64
63
  def __init__(self, *args, **kwargs) -> None:
65
64
  super().__init__(*args, **kwargs)
66
- self.main_queue = self._create_queue("main")
67
- self.error_queue = self._create_queue("error")
65
+ self._main_queue = self._create_queue("main")
66
+ self._error_queue = self._create_queue("error")
68
67
 
69
68
  def __str__(self) -> str:
70
69
  return self.name
@@ -78,8 +77,8 @@ class Webhook(models.Model):
78
77
  # method to avoid modifying the original state.
79
78
  state = self.__dict__.copy()
80
79
  # Remove the unpicklable entries.
81
- del state["main_queue"]
82
- del state["error_queue"]
80
+ del state["_main_queue"]
81
+ del state["_error_queue"]
83
82
  return state
84
83
 
85
84
  def __setstate__(self, state):
@@ -87,15 +86,15 @@ class Webhook(models.Model):
87
86
  self.__dict__.update(state)
88
87
  # Restore the previously opened file's state. To do so, we need to
89
88
  # reopen it and read from it until the line count is restored.
90
- self.main_queue = self._create_queue("main")
91
- self.error_queue = self._create_queue("error")
89
+ self._main_queue = self._create_queue("main")
90
+ self._error_queue = self._create_queue("error")
92
91
 
93
92
  def save(self, *args, **kwargs):
94
93
  is_new = self.id is None # type: ignore
95
94
  super().save(*args, **kwargs)
96
95
  if is_new:
97
- self.main_queue = self._create_queue("main")
98
- self.error_queue = self._create_queue("error")
96
+ self._main_queue = self._create_queue("main")
97
+ self._error_queue = self._create_queue("error")
99
98
 
100
99
  def _create_queue(self, suffix: str) -> Optional[SimpleMQ]:
101
100
  redis_client = get_redis_client()
@@ -110,94 +109,70 @@ class Webhook(models.Model):
110
109
  returns number of moved messages.
111
110
  """
112
111
  counter = 0
113
- if self.error_queue and self.main_queue:
112
+ if self._error_queue and self._main_queue:
114
113
  while True:
115
- message = self.error_queue.dequeue()
114
+ message = self._error_queue.dequeue()
116
115
  if message is None:
117
116
  break
118
117
 
119
- self.main_queue.enqueue(message)
118
+ self._main_queue.enqueue(message)
120
119
  counter += 1
121
120
 
122
121
  return counter
123
122
 
124
- def enqueue_message(
125
- self,
126
- content: Optional[str] = None,
127
- embeds: Optional[List[dhooks_lite.Embed]] = None,
128
- tts: Optional[bool] = None,
129
- username: Optional[str] = None,
130
- avatar_url: Optional[str] = None,
131
- ) -> int:
132
- """Enqueues a message to be send with this webhook"""
133
- if not self.main_queue:
123
+ def enqueue_message(self, message: DiscordMessage, is_error: bool = False) -> int:
124
+ """Enqueues a discord message to be send with this webhook.
125
+
126
+ Returns the updated number of messages in the main queue.
127
+ """
128
+ q = self._error_queue if is_error else self._main_queue
129
+
130
+ if not q:
134
131
  return 0
135
132
 
136
- username = __title__ if KILLTRACKER_WEBHOOK_SET_AVATAR else username
137
- brand_url = static_file_absolute_url("killtracker/killtracker_logo.png")
138
- avatar_url = brand_url if KILLTRACKER_WEBHOOK_SET_AVATAR else avatar_url
139
- return self.main_queue.enqueue(
140
- self._discord_message_asjson(
141
- content=content,
142
- embeds=embeds,
143
- tts=tts,
144
- username=username,
145
- avatar_url=avatar_url,
146
- )
147
- )
133
+ if KILLTRACKER_WEBHOOK_SET_AVATAR:
134
+ message.username = __title__
148
135
 
149
- @staticmethod
150
- def _discord_message_asjson(
151
- content: Optional[str] = None,
152
- embeds: Optional[List[dhooks_lite.Embed]] = None,
153
- tts: Optional[bool] = None,
154
- username: Optional[str] = None,
155
- avatar_url: Optional[str] = None,
156
- ) -> str:
157
- """Converts a Discord message to JSON and returns it
158
-
159
- Raises ValueError if message is incomplete
160
- """
161
- if not content and not embeds:
162
- raise ValueError("Message must have content or embeds to be valid")
163
-
164
- if embeds:
165
- embeds_list = [obj.asdict() for obj in embeds]
166
- else:
167
- embeds_list = None
168
-
169
- message = {}
170
- if content:
171
- message["content"] = content
172
- if embeds_list:
173
- message["embeds"] = embeds_list
174
- if tts:
175
- message["tts"] = tts
176
- if username:
177
- message["username"] = username
178
- if avatar_url:
179
- message["avatar_url"] = avatar_url
180
-
181
- return json.dumps(message, cls=JSONDateTimeEncoder)
182
-
183
- def send_message_to_webhook(self, message_json: str) -> dhooks_lite.WebhookResponse:
184
- """Send given message to webhook
185
-
186
- Params
187
- message_json: Discord message encoded in JSON
136
+ if KILLTRACKER_WEBHOOK_SET_AVATAR:
137
+ brand_url = static_file_absolute_url("killtracker/killtracker_logo.png")
138
+ message.avatar_url = brand_url
139
+
140
+ return q.enqueue(message.to_json())
141
+
142
+ def dequeue_message(self, is_error: bool = False) -> Optional[DiscordMessage]:
143
+ """Dequeues a message from the main queue and return it.
144
+
145
+ Returns None if the queue is empty.
188
146
  """
147
+ q = self._error_queue if is_error else self._main_queue
148
+ s = q.dequeue()
149
+ if not s:
150
+ return None
151
+
152
+ return DiscordMessage.from_json(s)
153
+
154
+ def messages_queued(self, is_error: bool = False) -> int:
155
+ """Returns how many message are currently in the queue."""
156
+ q = self._error_queue if is_error else self._main_queue
157
+ if not q:
158
+ return 0
159
+
160
+ return q.size()
161
+
162
+ def delete_queued_messages(self, is_error: bool = False) -> int:
163
+ """Deletes all messages in a queue and returns how many messages where deleted."""
164
+ q = self._error_queue if is_error else self._main_queue
165
+ if not q:
166
+ return 0
167
+
168
+ return q.clear()
169
+
170
+ def send_message(self, message: DiscordMessage) -> dhooks_lite.WebhookResponse:
171
+ """Send a message to the webhook."""
189
172
  timeout = cache.ttl(self._blocked_cache_key()) # type: ignore
190
173
  if timeout:
191
174
  raise WebhookTooManyRequests(timeout)
192
175
 
193
- message = json.loads(message_json, cls=JSONDateTimeDecoder)
194
- if message.get("embeds"):
195
- embeds = [
196
- dhooks_lite.Embed.from_dict(embed_dict)
197
- for embed_dict in message.get("embeds")
198
- ]
199
- else:
200
- embeds = None
201
176
  hook = dhooks_lite.Webhook(
202
177
  url=self.url,
203
178
  user_agent=dhooks_lite.UserAgent(
@@ -205,16 +180,21 @@ class Webhook(models.Model):
205
180
  ),
206
181
  )
207
182
  response = hook.execute(
208
- content=message.get("content"),
209
- embeds=embeds,
210
- username=message.get("username"),
211
- avatar_url=message.get("avatar_url"),
183
+ content=message.content,
184
+ embeds=message.embeds,
185
+ username=message.username,
186
+ avatar_url=message.avatar_url,
212
187
  wait_for_response=True,
213
188
  max_retries=0, # we will handle retries ourselves
214
189
  )
215
- logger.debug("headers: %s", response.headers)
216
- logger.debug("status_code: %s", response.status_code)
217
- logger.debug("content: %s", response.content)
190
+ logger.debug(
191
+ "%s: Response from Discord for creating message from killmail %d: %s %s %s",
192
+ self,
193
+ message.killmail_id,
194
+ response.status_code,
195
+ response.headers,
196
+ response.content,
197
+ )
218
198
  if response.status_code == self.HTTP_TOO_MANY_REQUESTS:
219
199
  logger.error(
220
200
  "%s: Received too many requests error from API: %s",
@@ -229,6 +209,7 @@ class Webhook(models.Model):
229
209
  key=self._blocked_cache_key(), value="BLOCKED", timeout=retry_after
230
210
  )
231
211
  raise WebhookTooManyRequests(retry_after)
212
+
232
213
  return response
233
214
 
234
215
  def _blocked_cache_key(self) -> str:
killtracker/providers.py CHANGED
@@ -5,7 +5,7 @@ from esi.clients import EsiClientProvider
5
5
  from allianceauth.services.hooks import get_extension_logger
6
6
  from app_utils.logging import LoggerAddTag
7
7
 
8
- from . import USER_AGENT_TEXT, __title__
8
+ from killtracker import USER_AGENT_TEXT, __title__
9
9
 
10
10
  logger = LoggerAddTag(get_extension_logger(__name__), __title__)
11
11
 
killtracker/signals.py ADDED
@@ -0,0 +1,31 @@
1
+ """Module signals connects to celery signals."""
2
+
3
+ # pylint: disable=missing-function-docstring
4
+
5
+ from celery import signals
6
+
7
+ from allianceauth.services.hooks import get_extension_logger
8
+ from app_utils.logging import LoggerAddTag
9
+
10
+ from killtracker import __title__
11
+ from killtracker.core import worker_shutdown
12
+
13
+ logger = LoggerAddTag(get_extension_logger(__name__), __title__)
14
+
15
+
16
+ @signals.worker_ready.connect
17
+ def worker_ready_handler(sender, **kwargs):
18
+ worker_shutdown.reset(sender.hostname)
19
+ logger.debug("worker_ready: %s", sender.hostname)
20
+
21
+
22
+ @signals.worker_shutting_down.connect
23
+ def worker_shutting_down_handler(sender, **kwargs):
24
+ worker_shutdown.set(sender)
25
+ logger.debug("worker_shutting_down: %s", sender)
26
+
27
+
28
+ @signals.worker_shutdown.connect
29
+ def worker_shutdown_handler(sender, **kwargs):
30
+ worker_shutdown.reset(sender.hostname)
31
+ logger.debug("worker_shutdown: %s", sender.hostname)