Django Cron Job Error: "[Errno 98] Address Already in Use" при использовании API Spotify с django-crontab
Я работаю над проектом Django, в котором я использую задание cron для управления плейлистами Spotify с помощью Spotify API. Задание cron планируется с помощью django-crontab
и предназначено для добавления треков в несколько списков воспроизведения Spotify на разных аккаунтах.
Проблема: Задание cron работает нормально до определенного момента, но я постоянно сталкиваюсь со следующей ошибкой:
ERROR 2024-09-06 01:11:02,768 cron Error adding tracks: [Errno 98] Address already in use
ERROR 2024-09-06 01:11:07,771 cron Error adding tracks: [Errno 98] Address already in use
ERROR 2024-09-06 01:11:12,774 cron Error adding tracks: [Errno 98] Address already in use
То, что я пробовал:
- Окружение: Я использую Ubuntu с Django, django-crontab и Spotipy (Python-клиент для Spotify Web API).
- Spotify Web API Sandbox: Я тестировал API с spotify web API и там он работает нормально.
- Анализ ошибки: Ошибка возникает после сообщения в журнале о том, что идентификатор пользователя используется для добавления треков в плейлист. Следующий блок попыток не выполняется, и возникает ошибка [Errno 98] Address already in use.
- Проверка конфликта портов: Сначала я подумал, что ошибка может быть связана с конфликтом портов с сервером Django, работающим на порту 8000, но я понял, что мой сервер Django должен работать на этом порту, поэтому проверка его использования не требуется.
- Обработка ошибок и повторные попытки: Я реализовал логику повторных попыток для обработки таких исключений, как ограничения скорости Spotify API (429 Too Many Requests) и ошибки разрешения (403 Forbidden). Логика повторных попыток обрабатывает эти исключения правильно, но ошибка [Errno 98] Address already in use сохраняется.
def add_tracks_to_playlist(order, playlist_id, track_uris, sp, spotify_account):
retries = 3
delay = 5
USER_ID = spotify_account.spotify_key.username
logger.info(f"Using user ID {USER_ID} to add tracks to playlist {playlist_id}")
for attempt in range(retries):
try:
logger.debug(f"Attempting to add {len(track_uris)} tracks to playlist {playlist_id}, attempt {attempt + 1}")
sp.user_playlist_add_tracks(USER_ID, playlist_id, track_uris)
logger.info(f"Successfully added {len(track_uris)} tracks to playlist {playlist_id} for user {order.user_id}")
update_order_status(order)
break # Exit the loop if successful
except SpotifyException as e:
logger.error(f"Spotify API error: {e.msg}")
logger.debug(f"Spotify API response: {e}")
if e.http_status == 403:
logger.error(f"Check if the user {USER_ID} is correctly registered and has permissions to modify the playlist.")
return # Exit further retries as this is likely a permissions issue
if e.http_status == 429: # Rate limit exceeded
retry_after = int(e.headers.get('Retry-After', delay))
logger.info(f"Rate limit exceeded. Retrying after {retry_after} seconds.")
time.sleep(retry_after)
except OSError as e:
if e.errno == 98: # Address already in use
logger.error(f"Error adding tracks: Address already in use. Retrying after {delay} seconds.")
time.sleep(delay)
else:
logger.error(f"OS Error: {e}")
logger.debug(f"Detailed OS exception: {repr(e)}")
time.sleep(delay)
except Exception as e:
logger.error(f"Error adding tracks: {e}")
logger.debug(f"Detailed exception: {repr(e)}")
time.sleep(delay)
else:
logger.error(f"Failed to add tracks to playlist {playlist_id} after {retries} attempts.")
Журнал выполнения заданий
INFO 2024-09-06 15:29:01,639 cron Cron started
INFO 2024-09-06 15:29:01,640 cron Cron job started.
INFO 2024-09-06 15:29:01,644 cron 1 pending orders found.
INFO 2024-09-06 15:29:01,646 cron Processing Order ID 35 with 1 playlists.
INFO 2024-09-06 15:29:01,653 cron Initializing Spotify client for user myuserid with Client ID: myclientid
INFO 2024-09-06 15:29:01,654 cron Successfully initialized SpotifyOAuth for user.
INFO 2024-09-06 15:29:01,654 cron Assigned jobs: [1]
INFO 2024-09-06 15:29:01,655 cron Distributing 1 playlists to job scheduled at 2024-09-06 15:38:01.655010 for Order ID 35.
INFO 2024-09-06 15:29:01,655 cron Adding track 4jYwFHigUt3c21ATMklTku to playlist 4ZwEDixe0VTBSCHfLLqKoH
ERROR 2024-09-06 15:29:01,659 cron Error adding tracks: [Errno 98] Address already in use
ERROR 2024-09-06 15:29:06,662 cron Error adding tracks: [Errno 98] Address already in use
ERROR 2024-09-06 15:29:11,668 cron Error adding tracks: [Errno 98] Address already in use
Согласно логу cronjob работает нормально до этой строки кода logger.info(f"Using user ID {USER_ID} to add tracks to playlist {playlist_id}")
, но когда он пытается добавить песню в плейлист spotify с помощью функции spotipy sp.user_playlist_add_tracks(USER_ID, playlist_id, track_uris)
, он выдает мне OS Error 98
Дополнительная информация:
sudo lsof -i -n -P | grep LISTEN
systemd-r 605 systemd-resolve 14u IPv4 18718 0t0 TCP 127.0.0.53:53 (LISTEN)
cupsd 916 root 6u IPv6 21045 0t0 TCP [::1]:631 (LISTEN)
cupsd 916 root 7u IPv4 21046 0t0 TCP 127.0.0.1:631 (LISTEN)
postman-a 13327 a-h-m-a-r 71u IPv4 111201 0t0 TCP 127.0.0.1:10533 (LISTEN)
python 25924 a-h-m-a-r 8u IPv4 224162 0t0 TCP 127.0.0.1:8000 (LISTEN)
- Ошибка возникает периодически и, похоже, связана с обработкой сети или сокетов.
- Задание cron предназначено для запуска через определенные промежутки времени, и у меня есть блокировка на основе кэша, чтобы гарантировать, что только один экземпляр запускается в одно время.
Моя установка:
- Django Версия: последняя
- Python Версия: 3.12
- Spotipy для добавления песен в плейлист
- OS: Ubuntu 20.04
- Инструменты:
django-crontab
для планирования задания cron
Вопрос:
- Что может вызвать ошибку
[Errno 98] Address already in use
в контексте моего задания cron? - Как я могу изменить свой код или настройку задания cron, чтобы избежать этой ошибки и обеспечить надежное выполнение задания?
- Существуют ли лучшие практики или альтернативные подходы для обработки таких ошибок, связанных с сетью, в среде cron job в Django?
Образец запроса Wget:
wget --quiet \
--method POST \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer 1POdFZRZbvb...qqillRxMr2z' \
--body-data '{\n "uris": [\n "3yHyiUDJdz02FZ6jfUbsmY"\n ],\n "position": 0\n}' \
--output-document \
- 'https://api.spotify.com/v1/playlists/4ZwEDixe0VTBSCHfLLqKoH/tracks?uris=spotify%3Atrack%3A3yHyiUDJdz02FZ6jfUbsmY'
Настройка кронтаба в settings.py
CRONJOBS = [
('*/5 * * * *', 'app.cronjob.cron.my_scheduled_job'),
]
CRONTAB_LOCK_JOBS = True