Skip to content

Instantly share code, notes, and snippets.

@peterrus
Created March 13, 2022 11:56
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save peterrus/d60ba5ede3385712cbaea753e5fa5a47 to your computer and use it in GitHub Desktop.
Save peterrus/d60ba5ede3385712cbaea753e5fa5a47 to your computer and use it in GitHub Desktop.
Runs a scheduled job in a background thread using APScheduler and streams it's output to a web client using websockets.
# Runs a scheduled job in a background thread using APScheduler and streams
# it's output to a web client using websockets. Communication between the Flask
# thread and APScheduler thread is being done through (blinker) signals.
#
# Install dependencies (preferably in your virtualenv)
# pip install flask apscheduler sqlalchemy blinker flask-socketio simple-websocket
# and then run with:
# python this_script.py
from time import sleep
from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
from apscheduler.schedulers.background import BackgroundScheduler
from blinker import signal
from flask import Flask
from flask_socketio import SocketIO
from pytz import utc
# initialize Flask+SocketIO
app = Flask(__name__)
socketio = SocketIO(app)
# signal to communicate between background thread and Flask
logsignal = signal('log')
# handle signals coming from background thread and emit them
# over the websocket
@logsignal.connect
def send_log_update(log_line):
socketio.emit('logUpdate', log_line)
# Background job that will run in the scheduler thread
def background_job():
logsignal.send('starting job')
sleep(3)
logsignal.send('job done')
# configure APScheduler
jobstores = {
'default': SQLAlchemyJobStore(url='sqlite:///scheduler.sqlite')
}
job_defaults = {
'coalesce': False,
'max_instances': 1
}
# create and start scheduler
scheduler = BackgroundScheduler(
job_defaults=job_defaults, jobstores=jobstores, timezone=utc)
# simple websocket client for testing purposes
@app.route("/")
def info():
return """
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js" integrity="sha512-q/dWJ3kcmjBLU4Qc47E4A9kTB4m3wuTY7vkFJDTZKjTs8jhyGQnaUrxa0Ytd0ssMZhbNua9hE+E7Qv1j+DyZwA==" crossorigin="anonymous"></script>
</head>
<body>
<h1>Streaming log</h1>
<pre id="log"></pre>
<script type="text/javascript" charset="utf-8">
var socket = io();
socket.on('logUpdate', function(msg) {
let log = document.getElementById('log');
log.append(msg + '\\n');
});
</script>
</body>
</html>
"""
if __name__ == '__main__':
scheduler.add_job(background_job, 'interval', seconds=5,
replace_existing=True, id='sample_job',
args=[])
scheduler.start()
socketio.run(app)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment