【问题标题】:How to create a background task which runs forever -Python FlaskSQLAlchemy如何创建一个永远运行的后台任务-Python Flask SQLAlchemy
【发布时间】:2018-09-09 15:13:24
【问题描述】:

我想创建一个永远运行的简单后台任务。我会想办法在我用 Flask 编写的 Web 应用程序的同时启动它。

到目前为止,我所拥有的是:

import threading
from app.models import SkillTracker, UserAttributes
from flask_sqlalchemy import SQLAlchemy
from app import db
import time, math

class SkillTimer(threading.Thread, SkillTracker):
    def __init__(self, SkillTracker=SkillTracker):
        threading.Thread.__init__(self)
        self.skillcheck = SkillTracker.query.filter_by(isactive=1).all()
    def run(self):
            # for x in range(1, 1+1):
            #     if x%1 == 0:
            #         print(x)
            # #print(x)
            time.sleep(1)
            self.skillcheck = SkillTracker.query.filter_by(isactive=1).all()

            if self.skillcheck != []:
                print(self.skillcheck)
                for record in self.skillcheck:
                    if record.isactive == 1:
                        if record.timesubmit + record.timetowait <= time.time():
                            user = UserAttributes.query.filter_by(user_id=record.userid).first()
                            if record.targetskill == 'int':
                                record.isactive = 0
                                user.intelligence += 1
                                db.session.commit()
                                print('User {} upgraded {}, level = {} -- {}'.format(user.user_id, record.targetskill,
                                                                                     user.intelligence, time.time()))
                            if record.targetskill == 'end':
                                record.isactive = 0
                                user.endurance += 1
                                db.session.commit()
                                print('User {} upgraded {}, level = {} -- {}'.format(user.user_id, record.targetskill,
                                                                                     user.endurance, time.time()))
                            if record.targetskill == 'str':
                                record.isactive = 0
                                user.strength += 1
                                db.session.commit()
                                print('User {} upgraded {}, level = {} -- {}'.format(user.user_id, record.targetskill,
                                                                                     user.strength, time.time()))
            else:
                pass
            self.skillcheck = None
            skilltime = SkillTimer()
            skilltime.run()


#while True:
skilltime = SkillTimer()
skilltime.run()
#skilltimer.run()

这可以完美运行,正如您所期望的那样,但是,在它运行超过 ~950 次后我遇到了问题。我得到一个递归错误如下:

Traceback (most recent call last):
  File "D:\Anaconda3\lib\runpy.py", line 183, in _run_module_as_main
    mod_name, mod_spec, code = _get_module_details(mod_name, _Error)
  File "D:\Anaconda3\lib\runpy.py", line 109, in _get_module_details
    __import__(pkg_name)
  File "D:\Anaconda3\feuadal_kingdom\app\Skilltimer.py", line 52, in <module>
    skilltime.run()
  File "D:\Anaconda3\feuadal_kingdom\app\Skilltimer.py", line 47, in run
    skilltime.run()
  File "D:\Anaconda3\feuadal_kingdom\app\Skilltimer.py", line 47, in run
    skilltime.run()
  File "D:\Anaconda3\feuadal_kingdom\app\Skilltimer.py", line 47, in run
    skilltime.run()
  [Previous line repeated 923 more times]
  File "D:\Anaconda3\feuadal_kingdom\app\Skilltimer.py", line 46, in run
    skilltime = SkillTimer()
  File "<string>", line 4, in __init__
  File "D:\Anaconda3\lib\site-packages\sqlalchemy\orm\state.py", line 414, in _initialize_instance
    manager.dispatch.init_failure(self, args, kwargs)
  File "D:\Anaconda3\lib\site-packages\sqlalchemy\util\langhelpers.py", line 60, in __exit__
    compat.reraise(exc_type, exc_value, exc_tb)
  File "D:\Anaconda3\lib\site-packages\sqlalchemy\util\compat.py", line 187, in reraise
    raise value
  File "D:\Anaconda3\lib\site-packages\sqlalchemy\orm\state.py", line 411, in _initialize_instance
    return manager.original_init(*mixed[1:], **kwargs)
  File "D:\Anaconda3\feuadal_kingdom\app\Skilltimer.py", line 10, in __init__
    self.skillcheck = SkillTracker.query.filter_by(isactive=1).all()
  File "D:\Anaconda3\lib\site-packages\sqlalchemy\orm\query.py", line 2638, in all
    return list(self)
  File "D:\Anaconda3\lib\site-packages\sqlalchemy\orm\query.py", line 2790, in __iter__
    return self._execute_and_instances(context)
  File "D:\Anaconda3\lib\site-packages\sqlalchemy\orm\query.py", line 2813, in _execute_and_instances
    result = conn.execute(querycontext.statement, self._params)
  File "D:\Anaconda3\lib\site-packages\sqlalchemy\engine\base.py", line 945, in execute
    return meth(self, multiparams, params)
  File "D:\Anaconda3\lib\site-packages\sqlalchemy\sql\elements.py", line 263, in _execute_on_connection
    return connection._execute_clauseelement(self, multiparams, params)
  File "D:\Anaconda3\lib\site-packages\sqlalchemy\engine\base.py", line 1046, in _execute_clauseelement
    if not self.schema_for_object.is_default else None)
  File "<string>", line 1, in <lambda>
  File "D:\Anaconda3\lib\site-packages\sqlalchemy\sql\elements.py", line 436, in compile
    return self._compiler(dialect, bind=bind, **kw)
  File "D:\Anaconda3\lib\site-packages\sqlalchemy\sql\elements.py", line 442, in _compiler
    return dialect.statement_compiler(dialect, self, **kw)
  File "D:\Anaconda3\lib\site-packages\sqlalchemy\sql\compiler.py", line 435, in __init__
    Compiled.__init__(self, dialect, statement, **kwargs)
  File "D:\Anaconda3\lib\site-packages\sqlalchemy\sql\compiler.py", line 216, in __init__
    self.string = self.process(self.statement, **compile_kwargs)
  File "D:\Anaconda3\lib\site-packages\sqlalchemy\sql\compiler.py", line 242, in process
    return obj._compiler_dispatch(self, **kwargs)
  File "D:\Anaconda3\lib\site-packages\sqlalchemy\sql\visitors.py", line 81, in _compiler_dispatch
    return meth(self, **kw)
  File "D:\Anaconda3\lib\site-packages\sqlalchemy\sql\compiler.py", line 1738, in visit_select
    text, select, inner_columns, froms, byfrom, kwargs)
  File "D:\Anaconda3\lib\site-packages\sqlalchemy\sql\compiler.py", line 1822, in _compose_select_body
    t = select._whereclause._compiler_dispatch(self, **kwargs)
  File "D:\Anaconda3\lib\site-packages\sqlalchemy\sql\visitors.py", line 81, in _compiler_dispatch
    return meth(self, **kw)
  File "D:\Anaconda3\lib\site-packages\sqlalchemy\sql\compiler.py", line 1025, in visit_binary
    return self._generate_generic_binary(binary, opstring, **kw)
  File "D:\Anaconda3\lib\site-packages\sqlalchemy\sql\compiler.py", line 1050, in _generate_generic_binary
    self, eager_grouping=eager_grouping, **kw)
  File "D:\Anaconda3\lib\site-packages\sqlalchemy\sql\visitors.py", line 81, in _compiler_dispatch
    return meth(self, **kw)
  File "D:\Anaconda3\lib\site-packages\sqlalchemy\sql\compiler.py", line 1183, in visit_bindparam
    name = self._truncate_bindparam(bindparam)
  File "D:\Anaconda3\lib\site-packages\sqlalchemy\sql\compiler.py", line 1239, in _truncate_bindparam
    bind_name = self._truncated_identifier("bindparam", bind_name)
  File "D:\Anaconda3\lib\site-packages\sqlalchemy\sql\compiler.py", line 1250, in _truncated_identifier
    anonname = name.apply_map(self.anon_map)
  File "D:\Anaconda3\lib\site-packages\sqlalchemy\sql\elements.py", line 4079, in apply_map
    return self % map_
  File "D:\Anaconda3\lib\site-packages\sqlalchemy\util\_collections.py", line 729, in __missing__
    self[key] = val = self.creator(key)
  File "D:\Anaconda3\lib\site-packages\sqlalchemy\sql\compiler.py", line 1269, in _process_anon
    return derived + "_" + str(anonymous_counter)
RecursionError: maximum recursion depth exceeded while getting the str of an object

这会杀死进程,我不敢传递异常,因为它的存在是有原因的。

我的问题是,有没有办法调整这个线程类,使其可以无限次运行?

我觉得这可以通过每次重新启动类线程来解决,但同样,我不完全确定如何创建这种无限循环。

唯一需要注意的是,目前我只是在测试,所以任何解决方案都应该可以被键盘中断。

如果您需要进一步说明,请告诉我,数据库模型或烧瓶路由中没有任何错误,一切都按照我的意愿完美运行,除了达到递归限制后出现的错误。例如。增加递归限制只会延迟错误,而不是解决它。

【问题讨论】:

    标签: python multithreading flask sqlalchemy


    【解决方案1】:

    我会这样改:

    import threading
    from app.models import SkillTracker, UserAttributes
    from flask_sqlalchemy import SQLAlchemy
    from app import db
    import time, math
    
    class SkillTimer(threading.Thread, SkillTracker):
        def __init__(self, SkillTracker=SkillTracker):
            threading.Thread.__init__(self)
            self.skillcheck = SkillTracker.query.filter_by(isactive=1).all()
        def run(self):
            while True:
                time.sleep(1)
                self.skillcheck = SkillTracker.query.filter_by(isactive=1).all()
    
                if self.skillcheck != []:
                    print(self.skillcheck)
                    for record in self.skillcheck:
                        if record.isactive == 1:
                            if record.timesubmit + record.timetowait <= time.time():
                                user = UserAttributes.query.filter_by(user_id=record.userid).first()
                                if record.targetskill == 'int':
                                    record.isactive = 0
                                    user.intelligence += 1
                                    db.session.commit()
                                    print('User {} upgraded {}, level = {} -- {}'.format(user.user_id, record.targetskill,
                                                                                         user.intelligence, time.time()))
                                if record.targetskill == 'end':
                                    record.isactive = 0
                                    user.endurance += 1
                                    db.session.commit()
                                    print('User {} upgraded {}, level = {} -- {}'.format(user.user_id, record.targetskill,
                                                                                         user.endurance, time.time()))
                                if record.targetskill == 'str':
                                    record.isactive = 0
                                    user.strength += 1
                                    db.session.commit()
                                    print('User {} upgraded {}, level = {} -- {}'.format(user.user_id, record.targetskill,
                                                                                         user.strength, time.time()))
                else:
                    pass
                self.skillcheck = None
    
    
    skilltime = SkillTimer()
    skilltime.run()
    

    【讨论】:

    • 现在运行它,如果我们达到约 950 次递归,将会通知您。如果我们这样做,我相信问题可以归因于一次线程的数量或类似的东西。如果这能解决问题,会通知您并接受 :) 感谢您的建议。到目前为止一切顺利。
    • 我想你已经修好了,谢谢@codeglow 会接受你的回答。
    猜你喜欢
    • 1970-01-01
    • 2017-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多