@basuser123 Про это не было написано в первом посте.
Значит можешь проверять количество элементов в ресурсе "Ресурсы - Количество элементов".
1 поток при количестве элементов 0 - делает то что нужно.
Все остальные потоки при том же условии - закрываются с ошибкой без перезапуска.
Нормальное завершение потока, из которого запускается асинхронная функция
-
В скрипте нужно отменять активации номеров. Если отменить номер незадолго после взятия, то сервис СМС вернет ошибку. Поэтому я сделал функцию, которая в течение 2 минут пробует отменить номер, и вызываю ее как асинхронную функцию. Чтобы отмена номера выполнялась как фоновая задача, и основные потоки ее не ждали.
Ожидаемое поведение: поток баса вызывает функцию отмены номера и, не дожидаясь результата асинхронной функции, запускает следующее выполнение.
Как работает по факту: поток вызывает функцию асинхронно, не дожидаясь ее завершения, выполняет действия до конца. Но не запускает следующее выполнение, а ждет пока асинхронная функция завершится.
Как можно сделать:
Вызывать асинхронную функцию из onApplicationStart, брать таски на отмену из какой-нибудь очереди, вроде базы данных или глобальной переменной. Но тогда будет ряд проблем:- Как понять, когда стопать функцию? Думал получать количество запущенных потоков, и когда их 0 и очередь пустая, останавливать. Но в БАСе вроде получить количество запущенных потоков нельзя.
- Создать глобальную переменную, в которой инкременировать на 1, когда поток запущен и уменьшать, когда останавливается. Но в случае непредвиденных ошибок счетчик уменьшаться не будет. Придется весь скрипт пихать в игнор, что затруднит уже дебаг.
- Накладные расходы в виде очереди, где надо хранить таски.
В общем, значительно проще запускать фоновую задачу из обычного потока, и передавать ей что нужно. Но очень странно, что поток ждет асинхронную функцию.
P.S. Написал тестовый шаблон, но он работает нормально, магия какая-то.
test_async_function.xml -
Так не ждите выполнения асинхронной - там по сути просто гет запрос ... даже если в цикле ... По идеи вообще один ...
-
@thepappo said in Нормальное завершение потока, из которого запускается асинхронная функция:
В скрипте нужно отменять активации номеров. Если отменить номер незадолго после взятия, то сервис СМС вернет ошибку.
Я написал отдельный скрипт, который по API получает номера, которые вот-вот истекут и отменяет их. Скрипт запускается в цикле каждую минуту.
Например, номер дается на 20 минут, поток в скрипте у меня не может взять номер на это время, а может, к примеру на 5 минут максимум, значит я могу смело отменять все номера, которые были взяты более 15 минут назад.
5 минут взяты для примера. Я знаю, что я беру номер из сервиса, что-то там делаю, жду смс-ку и все это занимает у меня максимум эти самые 5 минут.
Сам скрипт ни о каких потоках, скриптах и так далее понятия не имеет и работает автономно.
import logging import os import datetime import time from dotenv import load_dotenv from smsactivate.api import SMSActivateAPI # Configure logging logging.basicConfig(level=logging.DEBUG) logger = logging.getLogger("[sms_activate]") # Load environment variables from .env file ABS_PATH = os.path.dirname(os.path.abspath(__file__)) load_dotenv() def main(api_key: str, threshold_seconds: int = 15 * 60): """ Main function to check and process active activations. Args: api_key (str): API key for SMSActivate service. threshold_seconds (int): Threshold in seconds to consider activation time. Returns: None """ sa = SMSActivateAPI(api_key) sa.debug_mode = True # Get active activations activations = sa.getActiveActivations() if activations.get("error") == 'NO_ACTIVATIONS': logger.info("No pending activations found.") return False # Check if activations retrieval was successful if activations.get("status") != 'success': raise Exception("Activation status is not success") # Loop through active activations for one in activations["activeActivations"]: if one["smsCode"]: # Skip if activation is already used continue # Parse activation time activation_time_str = one["activationTime"] activation_time = datetime.datetime.strptime(activation_time_str, '%Y-%m-%d %H:%M:%S') current_time = datetime.datetime.now() # Calculate time difference in seconds time_difference = current_time - activation_time seconds_difference = time_difference.total_seconds() # Log the time difference logger.info("Seconds difference from activation time to now: %s" % seconds_difference) # Check if activation time exceeds threshold if seconds_difference > threshold_seconds: logger.info("Activation time exceeds threshold for: %s" % one) # Mark activation as used sa.setStatus(id=one["activationId"], status=8) if __name__ == '__main__': # Get SMS Activate API key from environment variables sms_activate_api_key = os.getenv("SMS_ACTIVATE_API_KEY") if not sms_activate_api_key: raise Exception('SMS_ACTIVATE_API_KEY environment variable not set') sms_activate_api_key = sms_activate_api_key.strip() time_to_sleep = 60 while True: try: main(api_key=sms_activate_api_key) except Exception as e: # Log any exceptions logger.error(e) # Wait for 60 seconds before checking again logger.info(f"Sleeping for {time_to_sleep} seconds") time.sleep(time_to_sleep) -
@thepappo понял, во все просто оказывается ... Сергедрын взял и все по полочкам разложил ... Я правда его задачи до конца не понял, по какой причине поток не может взять больше чем на пять, и почему если он не дождался не может отбить что не судьба, но главное все по уму, по науке ....
-
@Nicolas said in Нормальное завершение потока, из которого запускается асинхронная функция:
Так не ждите выполнения асинхронной
В том и прикол, что я не жду. В предыдущем посте шаблон выложил тестовый, он нормально работает. А рабочий - нет ). Очевидно, что-то накосячил я сам.
-
@thepappo said in Нормальное завершение потока, из которого запускается асинхронная функция:
@sergerdn так а при чем тут питон?
Можно реализовать эту логику на каком угодно языке.
И получить тоже самое, один автономный скрипт отмены и куча скриптов на BAS, что берут номера из смс-сервиса и не имеют никакой логики отмены их. Я пишу всякие утилиты на python, ты можешь писать на чем угодно.
-
@thepappo said in Нормальное завершение потока, из которого запускается асинхронная функция:
@Nicolas said in Нормальное завершение потока, из которого запускается асинхронная функция:
Так не ждите выполнения асинхронной
В том и прикол, что я не жду. В предыдущем посте шаблон выложил тестовый, он нормально работает. А рабочий - нет ). Очевидно, что-то накосячил я сам.
в ошибку и на фейл внутри асинхронной ...
-
@sergerdn said in Нормальное завершение потока, из которого запускается асинхронная функция:
один автономный скрипт отмены и куча скриптов на BAS
Я понимаю, что можно. Я выше и про запуск демона из onApplicationStart писал. И я сам пишу на питоне ). Но в данном случае надо было именно из потока запускать таску.