मेरे पास एक फ्लास्क वेब होस्टिंग है जिसमें cron
कमांड का उपयोग नहीं है ।
मैं हर घंटे कुछ पायथन फ़ंक्शन को कैसे निष्पादित कर सकता हूं?
मेरे पास एक फ्लास्क वेब होस्टिंग है जिसमें cron
कमांड का उपयोग नहीं है ।
मैं हर घंटे कुछ पायथन फ़ंक्शन को कैसे निष्पादित कर सकता हूं?
जवाबों:
आप APScheduler पैकेज (v3.5.3) BackgroundScheduler()
से उपयोग कर सकते हैं :
import time
import atexit
from apscheduler.schedulers.background import BackgroundScheduler
def print_date_time():
print(time.strftime("%A, %d. %B %Y %I:%M:%S %p"))
scheduler = BackgroundScheduler()
scheduler.add_job(func=print_date_time, trigger="interval", seconds=3)
scheduler.start()
# Shut down the scheduler when exiting the app
atexit.register(lambda: scheduler.shutdown())
ध्यान दें कि इनमें से दो शेड्यूलर लॉन्च किए जाएंगे जब फ्लास्क डीबग मोड में होगा। अधिक जानकारी के लिए, इस प्रश्न को देखें।
flask
पास App.runonce
या फ्लास्क धावक के App.runForNseconds
बीच स्विच हो सकता है schedule
, लेकिन यह मामला नहीं है, तो अभी के लिए एकमात्र तरीका यह उपयोग कर रहा है
आप APScheduler
अपने फ्लास्क एप्लिकेशन का उपयोग कर सकते हैं और इसके इंटरफेस के माध्यम से अपनी नौकरी चला सकते हैं:
import atexit
# v2.x version - see https://stackoverflow.com/a/38501429/135978
# for the 3.x version
from apscheduler.scheduler import Scheduler
from flask import Flask
app = Flask(__name__)
cron = Scheduler(daemon=True)
# Explicitly kick off the background thread
cron.start()
@cron.interval_schedule(hours=1)
def job_function():
# Do your work here
# Shutdown your cron thread if the web process is stopped
atexit.register(lambda: cron.shutdown(wait=False))
if __name__ == '__main__':
app.run()
lambda
भीतर क्यों है atexit.register
?
atexit.register
कॉल करने के लिए एक फ़ंक्शन की आवश्यकता होती है। अगर हमने अभी पास किया है cron.shutdown(wait=False)
तो हम कॉलिंग (जो शायद है ) का परिणाम पारित करेंगे । इसलिए इसके बजाय, हम एक शून्य-तर्क फ़ंक्शन पास करते हैं, और इसे एक नाम देने और एक बयान का उपयोग करने के बजाय और हम इसके साथ इनलाइन को पंजीकृत करते हैं (जो कि एक शून्य-तर्क फ़ंक्शन अभिव्यक्ति है )।cron.shutdown
None
def shutdown(): cron.shutdown(wait=False)
atexit.register(shutdown)
lambda:
मैं एप्लिकेशन शेड्यूलर्स की अवधारणा के साथ थोड़ा नया हूं, लेकिन मुझे यहां एपीसकिलर v3.3.1 के लिए क्या मिला , यह कुछ अलग है। मेरा मानना है कि नवीनतम संस्करणों के लिए, पैकेज संरचना, वर्ग के नाम, आदि बदल गए हैं, इसलिए मैं यहां एक ताजा समाधान डाल रहा हूं जिसे मैंने हाल ही में बनाया है, एक मूल फ्लास्क एप्लिकेशन के साथ एकीकृत किया गया है:
#!/usr/bin/python3
""" Demonstrating Flask, using APScheduler. """
from apscheduler.schedulers.background import BackgroundScheduler
from flask import Flask
def sensor():
""" Function for test purposes. """
print("Scheduler is alive!")
sched = BackgroundScheduler(daemon=True)
sched.add_job(sensor,'interval',minutes=60)
sched.start()
app = Flask(__name__)
@app.route("/home")
def home():
""" Function for test purposes. """
return "Welcome Home :) !"
if __name__ == "__main__":
app.run()
मैं भी इस सार जा रहा हूँ यहाँ , अगर किसी को भी इस उदाहरण के लिए अद्यतन पर ब्याज की है।
भविष्य में पढ़ने के लिए कुछ संदर्भ यहां दिए गए हैं:
apscheduler.schedulers.background
इसके द्वारा प्रदान किए गए अधिक विकल्पों का पता लगाने की सलाह देता हूं , क्योंकि यह संभव हो सकता है कि आप अपने आवेदन के लिए अन्य उपयोगी परिदृश्यों का सामना कर सकें। सादर।
आप अपने फ्लास्क ऐप में अंतराल की नौकरी को एकीकृत करने के लिए APScheduler's BackgroundScheduler का उपयोग करने का प्रयास कर सकते हैं । नीचे उदाहरण है जो ब्लूप्रिंट और ऐप फैक्टरी ( init .py) का उपयोग करता है :
from datetime import datetime
# import BackgroundScheduler
from apscheduler.schedulers.background import BackgroundScheduler
from flask import Flask
from webapp.models.main import db
from webapp.controllers.main import main_blueprint
# define the job
def hello_job():
print('Hello Job! The time is: %s' % datetime.now())
def create_app(object_name):
app = Flask(__name__)
app.config.from_object(object_name)
db.init_app(app)
app.register_blueprint(main_blueprint)
# init BackgroundScheduler job
scheduler = BackgroundScheduler()
# in your case you could change seconds to hours
scheduler.add_job(hello_job, trigger='interval', seconds=3)
scheduler.start()
try:
# To keep the main thread alive
return app
except:
# shutdown if app occurs except
scheduler.shutdown()
आशा करता हूँ की ये काम करेगा :)
संदर्भ :
एक सरल समाधान के लिए, आप एक मार्ग जैसे जोड़ सकते हैं
@app.route("/cron/do_the_thing", methods=['POST'])
def do_the_thing():
logging.info("Did the thing")
return "OK", 200
फिर एक यूनिक्स क्रोन जॉब जोड़ें जो समय-समय पर इस बिंदु पर पोस्ट करता है। उदाहरण के लिए, इसे मिनट में एक बार चलाने के लिए, टर्मिनल टाइप में crontab -e
और इस लाइन को जोड़ें:
* * * * * /opt/local/bin/curl -X POST https://YOUR_APP/cron/do_the_thing
(ध्यान दें कि कर्ल करने का रास्ता पूरा होना है, क्योंकि जब काम चलता है तो उसमें आपका पैट नहीं होगा। आप अपने सिस्टम पर कर्ल करने का पूरा रास्ता पता कर सकते हैं which curl
)
मुझे यह पसंद है कि नौकरी को मैन्युअल रूप से परीक्षण करना आसान है, इसकी कोई अतिरिक्त निर्भरता नहीं है और जैसा कि कुछ विशेष नहीं है, इसे समझना आसान है।
यदि आप अपने क्रोन जॉब की रक्षा करना चाहते हैं pip install Flask-BasicAuth
, तो आप कर सकते हैं और फिर अपने ऐप कॉन्फ़िगरेशन में क्रेडेंशियल्स जोड़ सकते हैं :
app = Flask(__name__)
app.config['BASIC_AUTH_REALM'] = 'realm'
app.config['BASIC_AUTH_USERNAME'] = 'falken'
app.config['BASIC_AUTH_PASSWORD'] = 'joshua'
पासवर्ड के लिए जॉब एंडपॉइंट की सुरक्षा करें:
from flask_basicauth import BasicAuth
basic_auth = BasicAuth(app)
@app.route("/cron/do_the_thing", methods=['POST'])
@basic_auth.required
def do_the_thing():
logging.info("Did the thing a bit more securely")
return "OK", 200
फिर अपने क्रोन नौकरी से इसे कॉल करने के लिए:
* * * * * /opt/local/bin/curl -X POST https://falken:joshua@YOUR_APP/cron/do_the_thing
एक अन्य विकल्प फ्लास्क- APScheduler का उपयोग करना हो सकता है जो फ्लास्क के साथ अच्छी तरह से खेलता है, जैसे:
अधिक जानकारी यहाँ:
एक पूर्ण उदाहरण शेड्यूल और मल्टीप्रोसेसिंग का उपयोग करके, चालू और बंद नियंत्रण और रन_जॉब के पैरामीटर के साथ () रिटर्न कोड सरल किए जाते हैं और अंतराल 10sec पर सेट किया जाता है, 2 घंटे के लिए बदल जाता every(2).hour.do()
है। अनुसूची काफी प्रभावशाली है यह बहाव नहीं करता है और शेड्यूलिंग करते समय मैंने इसे कभी भी 100ms से अधिक दूर नहीं देखा है। थ्रेडिंग के बजाय मल्टीप्रोसेसिंग का उपयोग करना क्योंकि इसमें समाप्ति की विधि है।
#!/usr/bin/env python3
import schedule
import time
import datetime
import uuid
from flask import Flask, request
from multiprocessing import Process
app = Flask(__name__)
t = None
job_timer = None
def run_job(id):
""" sample job with parameter """
global job_timer
print("timer job id={}".format(id))
print("timer: {:.4f}sec".format(time.time() - job_timer))
job_timer = time.time()
def run_schedule():
""" infinite loop for schedule """
global job_timer
job_timer = time.time()
while 1:
schedule.run_pending()
time.sleep(1)
@app.route('/timer/<string:status>')
def mytimer(status, nsec=10):
global t, job_timer
if status=='on' and not t:
schedule.every(nsec).seconds.do(run_job, str(uuid.uuid4()))
t = Process(target=run_schedule)
t.start()
return "timer on with interval:{}sec\n".format(nsec)
elif status=='off' and t:
if t:
t.terminate()
t = None
schedule.clear()
return "timer off\n"
return "timer status not changed\n"
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
आप इसे केवल जारी करके परीक्षण करते हैं:
$ curl http://127.0.0.1:5000/timer/on
timer on with interval:10sec
$ curl http://127.0.0.1:5000/timer/on
timer status not changed
$ curl http://127.0.0.1:5000/timer/off
timer off
$ curl http://127.0.0.1:5000/timer/off
timer status not changed
हर 10sec टाइमर पर है यह सांत्वना के लिए एक टाइमर संदेश जारी करेगा:
127.0.0.1 - - [18/Sep/2018 21:20:14] "GET /timer/on HTTP/1.1" 200 -
timer job id=b64ed165-911f-4b47-beed-0d023ead0a33
timer: 10.0117sec
timer job id=b64ed165-911f-4b47-beed-0d023ead0a33
timer: 10.0102sec
आप शेड्यूलर के साथ कुछ कतार तंत्र का उपयोग करना चाह सकते हैं जैसे कि आरक्यू अनुसूचक या सेलेरी जैसे कुछ अधिक भारी (शायद एक ओवरकिल)।