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
Вернуться на верх