1625812600
Next.js Tutorial - 21 - Running Static Generation Builds
Running Static Generation Builds in Next.js
ð Courses - https://learn.codevolution.dev/
â¡ïž Checkout Taskade! https://www.taskade.com/
ð Support - https://www.paypal.me/Codevolution
ðŸ Github - https://github.com/gopinav
ð± Follow Codevolution
â Kite Code Completion - https://www.kite.com/get-kite/?utm_medium=referral&utm_source=youtube&utm_campaign=codevolution&utm_content=description-only
ð« Business - codevolution.business@gmail.com
#next #react
1632537859
Not babashka. Node.js babashka!?
Ad-hoc CLJS scripting on Node.js.
Experimental. Please report issues here.
Nbb's main goal is to make it easy to get started with ad hoc CLJS scripting on Node.js.
Additional goals and features are:
Nbb requires Node.js v12 or newer.
CLJS code is evaluated through SCI, the same interpreter that powers babashka. Because SCI works with advanced compilation, the bundle size, especially when combined with other dependencies, is smaller than what you get with self-hosted CLJS. That makes startup faster. The trade-off is that execution is less performant and that only a subset of CLJS is available (e.g. no deftype, yet).
Install nbb
from NPM:
$ npm install nbb -g
Omit -g
for a local install.
Try out an expression:
$ nbb -e '(+ 1 2 3)'
6
And then install some other NPM libraries to use in the script. E.g.:
$ npm install csv-parse shelljs zx
Create a script which uses the NPM libraries:
(ns script
(:require ["csv-parse/lib/sync$default" :as csv-parse]
["fs" :as fs]
["path" :as path]
["shelljs$default" :as sh]
["term-size$default" :as term-size]
["zx$default" :as zx]
["zx$fs" :as zxfs]
[nbb.core :refer [*file*]]))
(prn (path/resolve "."))
(prn (term-size))
(println (count (str (fs/readFileSync *file*))))
(prn (sh/ls "."))
(prn (csv-parse "foo,bar"))
(prn (zxfs/existsSync *file*))
(zx/$ #js ["ls"])
Call the script:
$ nbb script.cljs
"/private/tmp/test-script"
#js {:columns 216, :rows 47}
510
#js ["node_modules" "package-lock.json" "package.json" "script.cljs"]
#js [#js ["foo" "bar"]]
true
$ ls
node_modules
package-lock.json
package.json
script.cljs
Nbb has first class support for macros: you can define them right inside your .cljs
file, like you are used to from JVM Clojure. Consider the plet
macro to make working with promises more palatable:
(defmacro plet
[bindings & body]
(let [binding-pairs (reverse (partition 2 bindings))
body (cons 'do body)]
(reduce (fn [body [sym expr]]
(let [expr (list '.resolve 'js/Promise expr)]
(list '.then expr (list 'clojure.core/fn (vector sym)
body))))
body
binding-pairs)))
Using this macro we can look async code more like sync code. Consider this puppeteer example:
(-> (.launch puppeteer)
(.then (fn [browser]
(-> (.newPage browser)
(.then (fn [page]
(-> (.goto page "https://clojure.org")
(.then #(.screenshot page #js{:path "screenshot.png"}))
(.catch #(js/console.log %))
(.then #(.close browser)))))))))
Using plet
this becomes:
(plet [browser (.launch puppeteer)
page (.newPage browser)
_ (.goto page "https://clojure.org")
_ (-> (.screenshot page #js{:path "screenshot.png"})
(.catch #(js/console.log %)))]
(.close browser))
See the puppeteer example for the full code.
Since v0.0.36, nbb includes promesa which is a library to deal with promises. The above plet
macro is similar to promesa.core/let
.
$ time nbb -e '(+ 1 2 3)'
6
nbb -e '(+ 1 2 3)' 0.17s user 0.02s system 109% cpu 0.168 total
The baseline startup time for a script is about 170ms seconds on my laptop. When invoked via npx
this adds another 300ms or so, so for faster startup, either use a globally installed nbb
or use $(npm bin)/nbb script.cljs
to bypass npx
.
Nbb does not depend on any NPM dependencies. All NPM libraries loaded by a script are resolved relative to that script. When using the Reagent module, React is resolved in the same way as any other NPM library.
To load .cljs
files from local paths or dependencies, you can use the --classpath
argument. The current dir is added to the classpath automatically. So if there is a file foo/bar.cljs
relative to your current dir, then you can load it via (:require [foo.bar :as fb])
. Note that nbb
uses the same naming conventions for namespaces and directories as other Clojure tools: foo-bar
in the namespace name becomes foo_bar
in the directory name.
To load dependencies from the Clojure ecosystem, you can use the Clojure CLI or babashka to download them and produce a classpath:
$ classpath="$(clojure -A:nbb -Spath -Sdeps '{:aliases {:nbb {:replace-deps {com.github.seancorfield/honeysql {:git/tag "v2.0.0-rc5" :git/sha "01c3a55"}}}}}')"
and then feed it to the --classpath
argument:
$ nbb --classpath "$classpath" -e "(require '[honey.sql :as sql]) (sql/format {:select :foo :from :bar :where [:= :baz 2]})"
["SELECT foo FROM bar WHERE baz = ?" 2]
Currently nbb
only reads from directories, not jar files, so you are encouraged to use git libs. Support for .jar
files will be added later.
The name of the file that is currently being executed is available via nbb.core/*file*
or on the metadata of vars:
(ns foo
(:require [nbb.core :refer [*file*]]))
(prn *file*) ;; "/private/tmp/foo.cljs"
(defn f [])
(prn (:file (meta #'f))) ;; "/private/tmp/foo.cljs"
Nbb includes reagent.core
which will be lazily loaded when required. You can use this together with ink to create a TUI application:
$ npm install ink
ink-demo.cljs
:
(ns ink-demo
(:require ["ink" :refer [render Text]]
[reagent.core :as r]))
(defonce state (r/atom 0))
(doseq [n (range 1 11)]
(js/setTimeout #(swap! state inc) (* n 500)))
(defn hello []
[:> Text {:color "green"} "Hello, world! " @state])
(render (r/as-element [hello]))
Working with callbacks and promises can become tedious. Since nbb v0.0.36 the promesa.core
namespace is included with the let
and do!
macros. An example:
(ns prom
(:require [promesa.core :as p]))
(defn sleep [ms]
(js/Promise.
(fn [resolve _]
(js/setTimeout resolve ms))))
(defn do-stuff
[]
(p/do!
(println "Doing stuff which takes a while")
(sleep 1000)
1))
(p/let [a (do-stuff)
b (inc a)
c (do-stuff)
d (+ b c)]
(prn d))
$ nbb prom.cljs
Doing stuff which takes a while
Doing stuff which takes a while
3
Also see API docs.
Since nbb v0.0.75 applied-science/js-interop is available:
(ns example
(:require [applied-science.js-interop :as j]))
(def o (j/lit {:a 1 :b 2 :c {:d 1}}))
(prn (j/select-keys o [:a :b])) ;; #js {:a 1, :b 2}
(prn (j/get-in o [:c :d])) ;; 1
Most of this library is supported in nbb, except the following:
:syms
.-x
notation. In nbb, you must use keywords.See the example of what is currently supported.
See the examples directory for small examples.
Also check out these projects built with nbb:
See API documentation.
See this gist on how to convert an nbb script or project to shadow-cljs.
Prequisites:
To build:
bb release
Run bb tasks
for more project-related tasks.
Download Details:
Author: borkdude
Download Link: Download The Source Code
Official Website: https://github.com/borkdude/nbb
License: EPL-1.0
#node #javascript
1625674200
In this video, we are going to implement Google Analytics to our Next JS application. Tracking page views of an application is very important.
Google analytics will allow us to track analytics information.
Frontend: https://github.com/amitavroy/video-reviews
API: https://github.com/amitavdevzone/video-review-api
App link: https://video-reviews.vercel.app
You can find me on:
Twitter: https://twitter.com/amitavroy7â
Discord: https://discord.gg/Em4nuvQk
#next js #js #react js #react #next #google analytics
1625812600
Next.js Tutorial - 21 - Running Static Generation Builds
Running Static Generation Builds in Next.js
ð Courses - https://learn.codevolution.dev/
â¡ïž Checkout Taskade! https://www.taskade.com/
ð Support - https://www.paypal.me/Codevolution
ðŸ Github - https://github.com/gopinav
ð± Follow Codevolution
â Kite Code Completion - https://www.kite.com/get-kite/?utm_medium=referral&utm_source=youtube&utm_campaign=codevolution&utm_content=description-only
ð« Business - codevolution.business@gmail.com
#next #react
1633583160
åŸæ¥ã®Webã¢ããªã±ãŒã·ã§ã³ã¯æ¬è³ªçã«åæããŠããŸãã ãŠãŒã¶ãŒã¯ãã©ãŠã¶ãŒã«è¡šç€ºãããWebã€ã³ã¿ãŒãã§ãŒã¹ãæäœãããã©ãŠã¶ãŒã¯ãã®ãŠãŒã¶ãŒæäœã«åºã¥ããŠãµãŒããŒã«èŠæ±ãè¿ãããµãŒããŒã¯ãŠãŒã¶ãŒã®æ°ãã衚瀺ã§ãããã®èŠæ±ã«å¿çããŸãã
仿¥ãç¶æ³ã¯å€åããŸãããçŸä»£ã®Webãµã€ãã¯ãæ°åäžã®èšªåè ããã®èŠæ±ãåŠçããå¿ èŠããããŸãããããã®èŠæ±ã«ããŒã¿ããŒã¹ãŸãã¯WebãµãŒãã¹ãšã®å¯Ÿè©±ãå«ãŸããå Žåãå¿çæéãé·ããªããäœåãã®èšªåè ãåããªãœãŒã¹ã«ã¢ã¯ã»ã¹ããŠããå ŽåãWebãµã€ãã®ããã©ãŒãã³ã¹ãå€§å¹ ã«äœäžããå¯èœæ§ããããŸãã ããã§éåæWebãå©ãã«ãªããŸãã
éåææ§ãéžæãããšãã«ææ¡ã§ããå©ç¹ã®ããã€ããæ¬¡ã«ç€ºããŸãã
ãã®ãã¥ãŒããªã¢ã«ã§ã¯ãæ°ããèŠæ±ã«å¿çããWebãµãŒããŒã®æ©èœãå¶éããé·æéå®è¡ã¿ã¹ã¯ãåŠçããWebã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ãããšãã«çºçããäžè¬çãªèœãšã穎ã®1ã€ãå æããæ¹æ³ã説æããŸãã
ç°¡åãªè§£æ±ºçã¯ããããã®é·æéå®è¡ã¿ã¹ã¯ãããã¯ã°ã©ãŠã³ãã§éåæã«ãå¥ã®ã¹ã¬ãããŸãã¯ããã»ã¹å ã§å®è¡ããWebãµãŒããŒãè§£æŸããããšã§ãã
RedisãFlaskãCeleryãSocketIOãªã©ã®ããã€ãã®ã³ã³ããŒãã³ããæŽ»çšããŠãé·æéå®è¡ãããã¿ã¹ã¯ã®å®è¡ããªãããŒãããå®äºããããã¯ã©ã€ã¢ã³ãã«ãã®ã¹ããŒã¿ã¹ã瀺ãããã·ã¥éç¥ãéä¿¡ããŸãã
ãã®ãã¥ãŒããªã¢ã«ã§ã¯ãã³ã«ãŒãã³ã䜿çšããŠã³ãŒããåæã«å®è¡ã§ããasyncioPythonã®çµã¿èŸŒã¿ã©ã€ãã©ãªã«ã€ããŠã¯èª¬æããŠããŸããã
èŠä»¶ãæºãããããšã次ã®ã³ã³ããŒãã³ããæ©èœããŸãã
RedisïŒã¯ããªãŒãã³ãœãŒã¹ã®é«åºŠãªKey-Valueã¹ãã¢ã§ããã髿§èœã§ã¹ã±ãŒã©ãã«ãªWebã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããããã®é©åãªãœãªã¥ãŒã·ã§ã³ã§ãããããéç«ããã3ã€ã®äž»ãªç¹åŸŽããããŸãïŒ
Redisã¯ããŒã¿ããŒã¹ãå®å šã«ã¡ã¢ãªã«ä¿æããæ°žç¶æ§ã®ããã«ã®ã¿ãã£ã¹ã¯ã䜿çšããŸãã
å€ãã®Key-ValueããŒã¿ã¹ãã¢ãšæ¯èŒãããšãRedisã«ã¯æ¯èŒçè±å¯ãªããŒã¿åã®ã»ããããããŸãã
Redisã®ã€ã³ã¹ããŒã«ã¯ããã®ãã¥ãŒããªã¢ã«ã®ç¯å²å€ã§ãããã ããWindowsãã·ã³ã«ã€ã³ã¹ããŒã«ããã«ã¯ããã®ã¯ã€ãã¯ã¬ã€ãã«åŸãããšããå§ãããŸãã
LinuxãŸãã¯macOSã䜿çšããŠããå Žåã¯ã以äžã®ã³ãã³ãã®ãããããå®è¡ãããšãRedisãã»ããã¢ãããããŸãã
Ubuntu / DebianïŒ
$ sudo apt-get install redis-server
ããã¯OSïŒ
$ brew install redis
$ brew services start redis
泚æïŒ ãã®ãã¥ãŒããªã¢ã«ã§ã¯ãRedisããŒãžã§ã³3.0.504ã䜿çšããŠããŸã
ã»ããªïŒPythonã®äžçã§æã人æ°ã®ããããã¯ã°ã©ãŠã³ããžã§ããããŒãžã£ãŒã®1人ã§ãããªã¢ã«ã¿ã€ã æäœã«éç¹ã眮ããŠããŸãããã¹ã±ãžã¥ãŒãªã³ã°ããµããŒãããŠããŸããRedisãRabbitMQãªã©ã®ããã€ãã®ã¡ãã»ãŒãžãããŒã«ãŒãšäºææ§ãããããããã¥ãŒãµãŒãšã³ã³ã·ã¥ãŒããŒã®äž¡æ¹ãšããŠæ©èœã§ããŸãã
requirements.txt
ãã¡ã€ã«ã«Celeryãã€ã³ã¹ããŒã«ã ãŸãã
泚æïŒ ãã®ãã¥ãŒããªã¢ã«ã§ã¯ãCeleryããŒãžã§ã³4.4.7ã䜿çšããŠããŸãã
ãã®ãã¥ãŒããªã¢ã«ã§ã¯ãã¹ãã£ãã©ãŒã«ãã£ã³ã°ææ³ãæ¡çšããåæéä¿¡ãšéåæéä¿¡ã®éããããã³éåæéä¿¡ã®ããªãšãŒã·ã§ã³ãçè§£ããããã«ãäžé£ã®ããŸããŸãªã·ããªãªã«ã€ããŠèª¬æããŸãã
ãã¹ãŠã®ã·ããªãªã¯Flaskãã¬ãŒã ã¯ãŒã¯å ã§æç€ºãããŸãããã ãããããã®ã»ãšãã©ã¯ä»ã®Pythonãã¬ãŒã ã¯ãŒã¯ïŒDjangoãPyramidïŒã«ç°¡åã«ç§»æ€ã§ããŸãã
ãã®ãã¥ãŒããªã¢ã«ã«èå³ããããããããã«ã³ãŒãã«é£ã³èŸŒã¿ãããšæã å Žåã¯ããã®èšäºã§äœ¿çšãããŠããã³ãŒãã«ã€ããŠããã®Githubãªããžããªã«ã¢ã¯ã»ã¹ ããŠãã ããã
ç§ãã¡ã®ã¢ããªã±ãŒã·ã§ã³ã¯ä»¥äžã§æ§æãããŸãïŒ
app_sync.py
åæéä¿¡ã玹ä»ããããã°ã©ã ãapp_async1.py
ã¯ã©ã€ã¢ã³ããããŒãªã³ã°ã¡ã«ããºã ã䜿çšããŠãµãŒããŒåŽããã»ã¹ã®ãã£ãŒãããã¯ãèŠæ±ããå¯èœæ§ãããéåæãµãŒãã¹åŒã³åºãã瀺ãããã°ã©ã ãapp_async2.py
ã¯ã©ã€ã¢ã³ããžã®èªåãã£ãŒãããã¯ã䌎ãéåæãµãŒãã¹åŒã³åºãã瀺ãããã°ã©ã ãapp_async3.py
ã¯ã©ã€ã¢ã³ããžã®èªåãã£ãŒãããã¯ã䌎ããã¹ã±ãžã¥ãŒã«åŸã®éåæãµãŒãã¹åŒã³åºãã瀺ãããã°ã©ã ãã»ããã¢ããã«é£ã³èŸŒã¿ãŸãããããã¡ãã ãã·ã¹ãã ã«Python3ãã€ã³ã¹ããŒã«ããå¿ èŠããã ãŸããç§ã¯å¿ èŠãªã©ã€ãã©ãªãã€ã³ã¹ããŒã«ããä»®æ³ç°å¢ã䜿çšããŸãïŒãããŠããªããééããªãããããã¹ãã§ãïŒïŒ
$ python -m venv async-venv
$ source async-venv/bin/activate
ååã®ä»ãããã¡ã€ã«ãäœæãã requirements.txt
ãã®äžã«æ¬¡ã®è¡ã远å ããŸãã
Flask==1.1.2
Flask-SocketIO==5.0.1
Celery==4.4.7
redis==3.5.3
gevent==21.1.2
gevent-websocket==0.10.1
flower==0.9.7
ä»ããããã€ã³ã¹ããŒã«ããŸãïŒ
$ pip install -r requirements.txt
ãã®ãã¥ãŒããªã¢ã«ãçµäºãããšããã©ã«ããŒæ§é ã¯æ¬¡ã®ããã«ãªããŸãã
ãããã¯ãªã¢ãããã®ã§ãå®éã®ã³ãŒããæžãå§ããŸãããã
ãŸããã¢ããªã±ãŒã·ã§ã³ã®æ§æãã©ã¡ãŒã¿ã次ã®ããã«å®çŸ©ããŸã config.py
ã
#config.py
#Application configuration File
################################
#Secret key that will be used by Flask for securely signing the session cookie
# and can be used for other security related needs
SECRET_KEY = 'SECRET_KEY'
#Map to REDIS Server Port
BROKER_URL = 'redis://localhost:6379'
#Minimum interval of wait time for our task
MIN_WAIT_TIME = 1
#Maximum interval of wait time for our task
MAX_WAIT_TIME = 20
泚æïŒç°¡æœã«ããããã«ããããã®æ§æãã©ã¡ãŒã¿ãŒãã«ããŒãã³ãŒãã£ã³ã°ããŸããã config.py
ããããã®ãã©ã¡ãŒã¿ãŒãå¥ã®ãã¡ã€ã«ïŒããšãã°.env
ïŒã«ä¿åããããšããå§ãããŸã ã
次ã«ããããžã§ã¯ãã®åæåãã¡ã€ã«ã次ã®å Žæã«äœæããŸã init.py
ã
#init.py
from flask import Flask
#Create a flask instance
app = Flask(__name__)
#Loads flask configurations from config.py
app.secret_key = app.config['SECRET_KEY']
app.config.from_object("config")
#Setup the Flask SocketIO integration (Required only for asynchronous scenarios)
from flask_socketio import SocketIO
socketio = SocketIO(app,logger=True,engineio_logger=True,message_queue=app.config['BROKER_URL'])
ã³ãŒãã£ã³ã°ã«å ¥ãåã«ãåæéä¿¡ã«ã€ããŠç°¡åã«èª¬æããŸãã
ã§åæéä¿¡ãçºåŒè ããµãŒãã¹ãèŠæ±ããå®å šã«ãµãŒãã¹ãåŸ ã¡åããŸãããã®ãµãŒãã¹ã®çµæãåãåã£ãå Žåã«ã®ã¿ãäœæ¥ãç¶è¡ããŸããã¿ã€ã ã¢ãŠããå®çŸ©ããŠãå®çŸ©ãããæéå ã«ãµãŒãã¹ãçµäºããªãå ŽåãåŒã³åºãã¯å€±æãããšèŠãªãããåŒã³åºãå ã¯ç¶è¡ããŸãã
åæéä¿¡ãã©ã®ããã«æ©èœããããçè§£ããããã«ãå°çšã®ãŠã§ã€ã¿ãŒãå²ãåœãŠããããšæ³åããŠãã ããã圌ã¯ããªãã®æ³šæãåãåããããããããã³ã«å±ããããã§ã·ã§ããããªãã®æçãæºåããã®ãåŸ ã¡ãŸãããã®éããŠã§ã€ã¿ãŒã¯äœãããŠããŸããã
次ã®å³ã¯ãåæãµãŒãã¹åŒã³åºãã瀺ããŠããŸãã
åæéä¿¡ã¯ã·ãŒã±ã³ã·ã£ã«ã¿ã¹ã¯ã«é©ããŠããŸãããåæã¿ã¹ã¯ã倿°ããå Žåãããã°ã©ã ã¯ã¹ã¬ããã䜿ãæãããã¹ã¬ããã䜿çšå¯èœã«ãªããŸã§æ°ããã¿ã¹ã¯ãåŸ æ©ãããå¯èœæ§ããããŸãã
ããã§ã¯ãã³ãŒãã£ã³ã°ã«åãæãããŸããããFlaskãã¬ã³ããªã³ã°ã§ãããã³ãã¬ãŒãïŒindex.html
ïŒãäœæãããã®äžã«æ¬¡ã®HTMLã³ãŒããå«ããŸãã
templates/index.html
<!DOCTYPE html>
<html>
<head>
<title>Synchronicity versus Asynchronicity</title>
<link rel="stylesheet" href="{{url_for('static',filename='css/materialize.min.css')}}">
<script src="{{ url_for('static',filename='js/jquery.min.js') }}"></script>
<script src="{{ url_for('static',filename='js/socket.io.js') }}"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
</head>
<body class="container">
<div class="row">
<h5>Click to start a post scheduled ansycnhronous task with automatic feedback.</h5>
</div>
<div class="card-panel">
<form method='post' id="runTaskForm" action="/runPSATask">
<div>
<input id="duration" name="duration" placeholder="Enter duration in seconds. for example: 30" type="text">
<label for="duration">Duration</label>
</div>
<button style="height:50px;width:600px" type="submit" id="runTask">Run A Post Scheduled Asynchronous Task With Automatic Feedback</button>
</form>
</div>
<div class="row">
<div id="Messages" class="red-text" style="width:800px; height:400px; overflow-y:scroll;"></div>
</div>
<script>
$(document).ready(function(){
var namespace='/runPSATask';
var url = 'http://' + document.domain + ':' + location.port + namespace;
var socket = io.connect(url);
socket.on('connect', function() {
socket.emit('join_room');
});
socket.on('msg' , function(data) {
$("#Messages").prepend('<li>'+data.msg+'</li>');
});
socket.on('status', function(data) {
////alert('socket on status ='+ data.msg);
if (data.msg == 'End') {
$("#runTask").attr("disabled",false);
};
});
});
</script>
<script>
$("#runTask").click(function(e) {
$("#runTask").attr("disabled",true);
$("#Messages").empty();
$.ajax({ type: "Post"
, url: '/runPSATask'
, data: $("#runTaskForm").serialize()
, success: function(data) {
$("#Messages").empty();
$("#Messages").prepend('<li>The Task ' + data.taskid + ' has been submitted and will execute in ' + data.duration + ' seconds. </li>');
}
});
e.preventDefault();
console.log('runPSATask complete');
});
</script>
</body>
</html>
ãã®ãã³ãã¬ãŒãã«ã¯æ¬¡ã®ãã®ãå«ãŸããŸãã
runTask
ã«ãŒãã䜿çšããŠãµãŒããŒã«ã¿ã¹ã¯ãéä¿¡ãããã¿ã³/runSyncTask
ãdiv
idã§ã«é
眮ããMessages
ãŸããæ¬¡ã«ãapp_sync.py
Flaskã¢ããªã±ãŒã·ã§ã³ãå«ããšããããã°ã©ã ãäœæãããã®ããã°ã©ã å
ã«2ã€ã®ã«ãŒããå®çŸ©ããŸãã
"/"
WebããŒãžãã¬ã³ããªã³ã°ããŸãïŒindex.html
ïŒ"/runSyncTask"
1ã20ç§ã®ä¹±æ°ãçæããå埩ããšã«1ç§éã¹ãªãŒãããã«ãŒããå®è¡ãããé·æéå®è¡äžã®ã¿ã¹ã¯ãã·ãã¥ã¬ãŒãããŸãã#app_sync.py
from flask import render_template, jsonify
from random import randint
from init import app
import tasks
#Render the predefined template index.html
@app.route("/",methods=['GET'])
def index():
return render_template('index.html')
#Defining the route for running A Synchronous Task
@app.route("/runSyncTask",methods=['POST'])
def long_sync_task():
print("Running","/runSyncTask")
#Generate a random number between MIN_WAIT_TIME and MAX_WAIT_TIME
n = randint(app.config['MIN_WAIT_TIME'],app.config['MAX_WAIT_TIME'])
#Call the function long_sync_task included within tasks.py
task = tasks.long_sync_task(n=n)
#Return the random wait time generated
return jsonify({ 'waittime': n })
if __name__ == "__main__":
app.run(debug=True)
ãã®ãã¥ãŒããªã¢ã«ã§å®çŸ©ãããŠãããã¹ãŠã®ã¿ã¹ã¯ã®ã³ã¢ããžãã¯ã¯ãããã°ã©ã å
ã«ãããŸãtasks.py
ã
#tasks.py
import time
from celery import Celery
from celery.utils.log import get_task_logger
from flask_socketio import SocketIO
import config
# Setup the logger (compatible with celery version 4)
logger = get_task_logger(__name__)
# Setup the celery client
celery = Celery(__name__)
# Load celery configurations from celeryconfig.py
celery.config_from_object("celeryconfig")
# Setup and connect the socket instance to Redis Server
socketio = SocketIO(message_queue=config.BROKER_URL)
###############################################################################
def long_sync_task(n):
print(f"This task will take {n} seconds.")
for i in range(n):
print(f"i = {i}")
time.sleep(1)
###############################################################################
@celery.task(name = 'tasks.long_async_task')
def long_async_task(n,session):
print(f"The task of session {session} will take {n} seconds.")
for i in range(n):
print(f"i = {i}")
time.sleep(1)
###############################################################################
def send_message(event, namespace, room, message):
print("Message = ", message)
socketio.emit(event, {'msg': message}, namespace=namespace, room=room)
@celery.task(name = 'tasks.long_async_taskf')
def long_async_taskf(data):
room = data['sessionid']
namespace = data['namespase']
n = data['waittime']
#Send messages signaling the lifecycle of the task
send_message('status', namespace, room, 'Begin')
send_message('msg', namespace, room, 'Begin Task {}'.format(long_async_taskf.request.id))
send_message('msg', namespace, room, 'This task will take {} seconds'.format(n))
print(f"This task will take {n} seconds.")
for i in range(n):
msg = f"{i}"
send_message('msg', namespace, room, msg )
time.sleep(1)
send_message('msg', namespace, room, 'End Task {}'.format(long_async_taskf.request.id))
send_message('status', namespace, room, 'End')
###############################################################################
@celery.task(name = 'tasks.long_async_sch_task')
def long_async_sch_task(data):
room = data['sessionid']
namespace = data['namespase']
n = data['waittime']
send_message('status', namespace, room, 'Begin')
send_message('msg' , namespace, room, 'Begin Task {}'.format(long_async_sch_task.request.id))
send_message('msg' , namespace, room, 'This task will take {} seconds'.format(n))
print(f"This task will take {n} seconds.")
for i in range(n):
msg = f"{i}"
send_message('msg', namespace, room, msg )
time.sleep(1)
send_message('msg' , namespace, room, 'End Task {}'.format(long_async_sch_task.request.id))
send_message('status', namespace, room, 'End')
###############################################################################
ãã®ã»ã¯ã·ã§ã³ã§ã¯ããã®long_sync_task()
颿°ãåæã¿ã¹ã¯ãšããŠã®ã¿äœ¿çšããŸãã
app_sync.py
ããã°ã©ã ãå®è¡ããŠãåæã·ããªãªããã¹ãããŠã¿ãŸãããã
$ python app_sync.py
http://localhost:5000
Flaskã€ã³ã¹ã¿ã³ã¹ãå®è¡ãããŠãããªã³ã¯ã«ã¢ã¯ã»ã¹ãããšã次ã®åºåã衚瀺ãããŸãã
ãåæã¿ã¹ã¯ã®å®è¡ããã¿ã³ãæŒããŠãããã»ã¹ãå®äºãããŸã§åŸ ã¡ãŸãã
å®äºãããšãããªã¬ãŒãããã¿ã¹ã¯ã«å²ãåœãŠãããã©ã³ãã ãªæéãéç¥ããã¡ãã»ãŒãžã衚瀺ãããŸãã
åæã«ããµãŒããŒãã¿ã¹ã¯ãå®è¡ãããšãã³ã³ãœãŒã«ã«1ç§ããšã«å¢åãããæ°å€ã衚瀺ãããŸãã
ãã®ã»ã¯ã·ã§ã³ã§ã¯ãã¯ã©ã€ã¢ã³ããããŒãªã³ã°ã¡ã«ããºã ã䜿çšããŠãµãŒããŒåŽããã»ã¹ã®ãã£ãŒãããã¯ãèŠæ±ããå¯èœæ§ã®ããéåæãµãŒãã¹åŒã³åºãã瀺ããŸãã
ç°¡åã«èšããšãéåæãšã¯ãããã°ã©ã ãç¹å®ã®ããã»ã¹ãå®äºããã®ãåŸ ããã«ãé¢ä¿ãªãç¶è¡ããããšãæå³ããŸãã
çºä¿¡è ãéå§ãµãŒãã¹ã³ãŒã«ããããES NçµæããªãåŸ ã¡æéãçºä¿¡è ã¯ãçµæãæ°ã«ããã«ããã«äœæ¥ãç¶è¡ããŸããçºä¿¡è ãçµæã«é¢å¿ãããå Žåã¯ãåŸã§èª¬æããã¡ã«ããºã ããããŸãã
æãåçŽãªéåæã¡ãã»ãŒãžäº€æãã¿ãŒã³ã¯ãã¡ã€ã¢ã¢ã³ããã©ãŒã²ãããšåŒã°ã ãã¡ãã»ãŒãžã¯éä¿¡ãããŸãããã£ãŒãããã¯ã¯å¿ èŠãããŸãããããã£ãŒãããã¯ãå¿ èŠãªå Žåãã¯ã©ã€ã¢ã³ãã¯ããŒãªã³ã°ã¡ã«ããºã ãä»ããŠçµæãç¹°ãè¿ãèŠæ±ããããšããããŸã ã
ããŒãªã³ã°ã¯æœåšçã«é«ããããã¯ãŒã¯è² è·ãåŒãèµ·ããããããå§ãããŸãããããã§ãããµãŒãã¹ãããã€ããŒïŒãµãŒããŒïŒãã¯ã©ã€ã¢ã³ãã«ã€ããŠç¥ãå¿ èŠããªããšããå©ç¹ããããŸãã
次ã®å³ã¯ãã·ããªãªã瀺ããŠããŸãã
éåæéä¿¡ã¯ãã€ãã³ãã«å¿çããå¿
èŠã®ããã³ãŒãïŒããšãã°ãåŸ
æ©ã䌎ãæéã®ãããI / OããŠã³ãæäœïŒã«é©ããŠããŸãã
éåææ§ãéžæãããšãã·ã¹ãã ã¯åæã«ããå€ãã®èŠæ±ãåŠçã§ããããã«ãªããã¹ã«ãŒããããåäžããŸãã
ããã§ã¯ãã³ãŒãã£ã³ã°ã«ç§»ããŸããããæ§æãã¡ã€ã«ã䜿çšããŠãã»ããªã®åæåãã©ã¡ãŒã¿ãŒãå®çŸ©ããŸãceleryconfig.py
ã
#celeryconfig.py
#Celery Configuration parameters
#Map to Redis server
broker_url = 'redis://localhost:6379/0'
#Backend used to store the tasks results
result_backend = 'redis://localhost:6379/0'
#A string identifying the default serialization to use Default json
task_serializer = 'json'
result_serializer = 'json'
accept_content = ['json']
#When set to false the local system timezone is used.
enable_utc = False
#To track the started state of a task, we should explicitly enable it
task_track_started = True
#Configure Celery to use a specific time zone.
#The timezone value can be any time zone supported by the pytz library
#timezone = 'Asia/Beirut'
#enable_utc = True
Flaskãã¬ã³ããªã³ã°ã§ãããã³ãã¬ãŒããäœæããŸãïŒindex1.html
ïŒïŒ
<!DOCTYPE html>
<html>
<head>
<title>Synchronicity versus Asynchronicity</title>
<link rel="stylesheet" href="{{url_for('static',filename='css/materialize.min.css')}}">
<script src="{{ url_for('static',filename='js/jquery.min.js') }}"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
</head>
<body class="container">
<div class="row">
<h4>Click to start an ansycnhronous task</h4>
</div>
<div class="card-panel">
<form method='post' id="runTaskForm" action="/runAsyncTask">
<button style="height:50px;width:400px" type="submit" id="runTask">Run An Asynchronous Task</button>
</form>
<form method='post' id="getTaskResultForm" action="/getAsyncTaskResult">
<button style="height:50px;width:400px" type="submit" id="getTaskResult">Get Asynchronous Task Result</button>
</form>
</div>
<div class="row">
<div id="Messages" class="red-text" style="width:800px; height:400px; overflow-y:scroll;"></div>
</div>
<script>
$("#runTask").click(function(e) {
$("#runTask").attr("disabled",true);
$("*").css("cursor","wait");
$("#Messages").empty();
$.ajax({ type: "Post"
, url: '/runAsyncTask'
, data: $("#runTaskForm").serialize()
, success: function(data) {
$("#runTask").attr("disabled",false);
$("*").css("cursor","");
$("#Messages").append('The task ' + data.taskid + ' will be executed in asynchronous manner for ' + data.waittime + ' seconds...');
}
});
e.preventDefault();
console.log('runAsyncTask complete');
});
$("#getTaskResult").click(function(e) {
var msg = $("#Messages").text();
var taskid = msg.match("task(.*)will");
//Get The Task ID from The Messages div and create a Target URL
var vurl = '/getAsyncTaskResult?taskid=' + jQuery.trim(taskid[1]);
$.ajax({ type: "Post"
, url: vurl
, data: $("#getTaskResultForm").serialize()
, success: function(data) {
$("*").css("cursor","");
$("#Messages").append('<p> The Status of the task = ' + data.taskid + ' is ' + data.taskstatus + '</p>');
}
});
e.preventDefault();
console.log('getAsyncTaskResult complete');
});
</script>
</body>
</html>
次ã«ãapp_async1.py
Flaskã¢ããªãå«ãããã°ã©ã ãäœæããŸãã
#app_async1.py
from flask import render_template, jsonify, session,request
from random import randint
import uuid
import tasks
from init import app
from celery.result import AsyncResult
@app.route("/",methods=['GET'])
def index():
# create a unique ID to assign for the asynchronous task
if 'uid' not in session:
sid = str(uuid.uuid4())
session['uid'] = sid
print("Session ID stored =", sid)
return render_template('index1.html')
#Run an Asynchronous Task
@app.route("/runAsyncTask",methods=['POST'])
def long_async_task():
print("Running", "/runAsyncTask")
#Generate a random number between MIN_WAIT_TIME and MAX_WAIT_TIME
n = randint(app.config['MIN_WAIT_TIME'],app.config['MAX_WAIT_TIME'])
sid = str(session['uid'])
task = tasks.long_async_task.delay(n=n,session=sid)
#print('taskid',task.id,'sessionid',sid,'waittime',n )
return jsonify({'taskid':task.id,'sessionid':sid,'waittime':n })
#Get The Result of The Asynchronous Task
@app.route('/getAsyncTaskResult', methods=['GET', 'POST'])
def result():
task_id = request.args.get('taskid')
# grab the AsyncResult
result = AsyncResult(task_id)
# print the task id
print("Task ID = ", result.task_id)
# print the Asynchronous result status
print("Task Status = ", result.status)
return jsonify({'taskid': result.task_id, 'taskstatus': result.status})
if __name__ == "__main__":
app.run(debug=True)
ãã®ããã°ã©ã ã«ã¯ã3ã€ã®äž»èŠãªã«ãŒãããããŸãã
"/"
ïŒWebããŒãžãã¬ã³ããªã³ã°ããŸãïŒindex1.html
ïŒã"/runAsyncTask"
ïŒ1ã20ç§ã®ä¹±æ°ãçæããéåæã¿ã¹ã¯ãåŒã³åºããŠãããå埩ããšã«1ç§éã¹ãªãŒãããã«ãŒããå®è¡ããŸãã"/getAsyncTaskResult"
ïŒåä¿¡ããã¿ã¹ã¯IDã«åºã¥ããŠãã¿ã¹ã¯ã®ç¶æ
ãåéããŸããæ³šæïŒãã®ã·ããªãªã«ã¯ãSocketIOã³ã³ããŒãã³ãã¯å«ãŸããŠããŸããã
ãã®ã·ããªãªããã¹ãããŠãæ¬¡ã®æé ã«åŸã£ãŠãã¹ãé²ããŸãããã
redis-server.exe
ãŸããããã©ã«ãã®ã€ã³ã¹ããŒã«ãŸãã¯Linux / MacOSã®å Žåã¯ãRedisã€ã³ã¹ã¿ã³ã¹ãTCPããŒã6379ã§å®è¡ãããŠããããšã確èªããŠãã ããã$ async-venv\Scripts\celery.exe worker -A tasks --loglevel=DEBUG --concurrency=1 -P solo -f celery.logs
Linux / MacOSã§ã¯ãéåžžã«ãã䌌ãŠããŸãã
$ async-venv/bin/celery worker -A tasks --loglevel=DEBUG --concurrency=1 -P solo -f celery.logs
ããasync-venv
ãä»®æ³ç°å¢ã®ååã§ããããšã«æ³šæããŠãã ãããå¥ã®ååãä»ããå Žåã¯ãå¿
ãèªåã®ååã«çœ®ãæããŠãã ãããã»ããªãå§ãŸããšã次ã®åºåã衚瀺ãããŸãã
ããã°ã©ã ã§å®çŸ©ãããã¿ã¹ã¯tasks.py
ãCeleryã«åæ ãããŠããããšã確èªããŠãã ããã
$ python app_async1.pyâ
次ã«ããã©ãŠã¶ãéããŠã次ã®ãªã³ã¯ã«ã¢ã¯ã»ã¹ããŸãã
[éåæã¿ã¹ã¯ã®å®è¡]ãã¿ã³ãæŒããšãæ°ããã¿ã¹ã¯ããã¥ãŒã«å ¥ããããçŽæ¥å®è¡ãããŸãããã¡ãã»ãŒãžãã»ã¯ã·ã§ã³ã«ãã¿ã¹ã¯ã®IDãšãã®å®è¡æéã瀺ãã¡ãã»ãŒãžã衚瀺ãããŸãã
[éåæã¿ã¹ã¯çµæã®ååŸ]ãã¿ã³ãïŒç¶ç¶çã«ïŒæŒããšããã®ç¹å®ã®æéã«ãããã¿ã¹ã¯ã®ç¶æ ãåéãããŸãã
ã»ããªã¿ã¹ã¯ã®çµã¿èŸŒã¿ç¶æ ã¯æ¬¡ã®ãšããã§ãã
PENDING
ïŒå®è¡ãåŸ
æ©ããŠããŸããSTARTED
ïŒã¿ã¹ã¯ãéå§ãããŸãããSUCCESS
ïŒã¿ã¹ã¯ã¯æ£åžžã«å®è¡ãããŸãããFAILURE
ïŒã¿ã¹ã¯ã®å®è¡ã«ããäŸå€ãçºçããŸãããRETRY
ïŒã¿ã¹ã¯ã¯å詊è¡ãããŠããŸããREVOKED
ïŒã¿ã¹ã¯ãåãæ¶ãããŸããããã°ãã¡ã€ã«ã«å«ãŸããŠããã»ããªã¯ãŒã«ãŒã®ãã°celery.logs
ã確èªãããšãã¿ã¹ã¯ã®ã©ã€ããµã€ã¯ã«ã«æ°ä»ãã§ãããã
以åã®ã·ããªãªã«åºã¥ããŠãã¿ã¹ã¯ã®ç¶æ ãåéããããã«è€æ°ã®ãªã¯ãšã¹ããéå§ããããšã«ããç ©ãããã軜æžããããã«ããµãŒããŒãã¿ã¹ã¯ã®ç¶æ ã«é¢ããŠã¯ã©ã€ã¢ã³ããç¶ç¶çã«æŽæ°ã§ããããã«ãããœã±ãããã¯ãããžã®çµã¿èŸŒã¿ã詊ã¿ãŸãã
å®éããœã±ããIOãšã³ãžã³ã¯ããªã¢ã«ã¿ã€ã ã®åæ¹åã€ãã³ãããŒã¹ã®éä¿¡ãå¯èœã«ããŸãã
ãããããããäž»ãªå©ç¹ã¯ããããã¯ãŒã¯ã®è² è·ã軜æžããèšå€§ãªæ°ã®ã¯ã©ã€ã¢ã³ãã«æ å ±ãäŒéããããã«ããå¹ççã«ãªãããšã§ãã
次ã®å³ã¯ãã·ããªãªã瀺ããŠããŸãã
ããã«æãäžããåã«ãå®è¡ããæé ã«ã€ããŠç°¡åã«èª¬æããŸãã
ã»ããªããWebãã©ãŠã¶ãŒã«ã¡ãã»ãŒãžãéãè¿ãããšãã§ããããã«ããããã«ã以äžã掻çšããŸãã
ããŒã¿æ¥ç¶ã广çã«ç®¡çããããã«ã次ã®åºååæŠç¥ãæ¡çšããŸãã
"/runAsyncTaskF"
ãã®ã·ããªãªã«åå空éãå²ãåœãŠãŸããïŒåå空éã¯ãåäžã®å
±ææ¥ç¶ãä»ããŠãµãŒããŒããžãã¯ãåé¢ããããã«äœ¿çšãããŸãïŒãããã§ã¯ãã³ãŒãã£ã³ã°ã«ç§»ããŸãããã
index2.html
ïŒïŒ<!DOCTYPE html>
<html>
<head>
<title>Synchronicity versus Asynchronicity</title>
<link rel="stylesheet" href="{{url_for('static',filename='css/materialize.min.css')}}">
<script src="{{ url_for('static',filename='js/jquery.min.js') }}"></script>
<script src="{{ url_for('static',filename='js/socket.io.js') }}"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body class="container">
<div class="row">
<h5>Click to start an ansycnhronous task with automatic feedback.</h5>
</div>
<div class="card-panel">
<form method='post' id="runTaskForm" action="/runAsyncTask">
<button style="height:50px;width:400px" type="submit" id="runTask">Run An Asynchronous Task With Automatic Feedback</button>
</form>
</div>
<div class="row">
<div id="Messages" class="red-text" style="width:800px; height:400px; overflow-y:scroll;"></div>
</div>
<script>
$(document).ready(function() {
var namespace = '/runAsyncTaskF';
var url = 'http://' + document.domain + ':' + location.port + namespace;
var socket = io.connect(url);
socket.on('connect', function() {
////alert('socket on connect');
socket.emit('join_room');
});
socket.on('msg', function(data) {
////alert('socket on msg ='+ data.msg);
$("#Messages").prepend('<li>' + data.msg + '</li>');
});
socket.on('status', function(data) {
////alert('socket on status ='+ data.msg);
if (data.msg == 'End') {
$("#runTask").attr("disabled", false);
};
});
});
</script>
<script>
$("#runTask").click(function(e) {
$("#runTask").attr("disabled", true);
$("*").css("cursor", "wait");
$("#Messages").empty();
$.ajax({
type: "Post",
url: '/runAsyncTaskF',
data: $("#runTaskForm").serialize(),
success: function(data) {
$("*").css("cursor", "");
$("#Messages").empty();
$("#Messages").prepend('<li>The Task ' + data.taskid + ' has been submitted. </li>');
}
});
e.preventDefault();
console.log('runAsyncTaskF complete');
});
</script>
</body>
</html>
app_async2.py
Flaskã¢ããªã±ãŒã·ã§ã³ãå«ããšåŒã°ããããã°ã©ã ãäœæããŸãã
#Gevent is a coroutine based concurrency library for Python
from gevent import monkey
#For dynamic modifications of a class or module
monkey.patch_all()
from flask import render_template, jsonify, session, request
from random import randint
import uuid
import tasks
from init import app, socketio
from flask_socketio import join_room
@app.route("/",methods=['GET'])
def index():
# create a unique session ID and store it within the Flask session
if 'uid' not in session:
sid = str(uuid.uuid4())
session['uid'] = sid
print("Session ID stored =", sid)
return render_template('index2.html')
#Run an Asynchronous Task With Automatic Feedback
@app.route("/runAsyncTaskF",methods=['POST'])
def long_async_taskf():
print("Running", "/runAsyncTaskF")
# Generate a random number between MIN_WAIT_TIME and MAX_WAIT_TIME
n = randint(app.config['MIN_WAIT_TIME'], app.config['MAX_WAIT_TIME'])
data = {}
data['sessionid'] = str(session['uid'])
data['waittime'] = n
data['namespase'] = '/runAsyncTaskF'
task = tasks.long_async_taskf.delay(data)
return jsonify({ 'taskid':task.id
,'sessionid':data['sessionid']
,'waittime':data['waittime']
,'namespace':data['namespase']
})
@socketio.on('connect', namespace='/runAsyncTaskF')
def socket_connect():
#Display message upon connecting to the namespace
print('Client Connected To NameSpace /runAsyncTaskF - ',request.sid)
@socketio.on('disconnect', namespace='/runAsyncTaskF')
def socket_connect():
# Display message upon disconnecting from the namespace
print('Client disconnected From NameSpace /runAsyncTaskF - ',request.sid)
@socketio.on('join_room', namespace='/runAsyncTaskF')
def on_room():
room = str(session['uid'])
# Display message upon joining a room specific to the session previously stored.
print(f"Socket joining room {room}")
join_room(room)
@socketio.on_error_default
def error_handler(e):
# Display message on error.
print(f"socket error: {e}, {str(request.event)}")
if __name__ == "__main__":
# Run the application with socketio integration.
socketio.run(app,debug=True)
ãã®ããã°ã©ã ã«ã¯ãäž»ã«2ã€ã®ã«ãŒãããããŸãã
"/"
ïŒWebããŒãžãã¬ã³ããªã³ã°ããŸãïŒindex2.html
ïŒã"/runAsyncTaskF"
ïŒä»¥äžãå®è¡ããéåæã¿ã¹ã¯ãåŒã³åºããŸããlong_async_taskf()
ããã°ã©ã å
ã®ããããã®ã¿ã¹ã¯ãåŒã³åºããŸãtasks.py
ããã®ã·ããªãªãå®è¡ããã«ã¯ïŒ
app_async2.py
ãã©ãŠã¶ãéããæ¬¡ã®ãªã³ã¯ã«ã¢ã¯ã»ã¹ããŠãã¿ã³ãæŒããšã次ã®ãããªåºåãåŸã ã«è¡šç€ºãããŸãã
åæã«ãã³ã³ãœãŒã«ã«æ¬¡ã®åºåã衚瀺ãããŸãã
ãŸã
celery.logs
ãã¿ã¹ã¯ã®ã©ã€ããµã€ã¯ã«ã«ã€ããŠãã¡ã€ã«ããã€ã§ã確èªã§ããŸãã
ãã®ã·ããªãªã¯ã·ããªãª3ã«äŒŒãŠããŸããå¯äžã®éãã¯ãéåæã¿ã¹ã¯ãçŽæ¥å®è¡ãã代ããã«ããã®ã¿ã¹ã¯ãã¯ã©ã€ã¢ã³ãã«ãã£ãŠæå®ãããç¹å®ã®æéã®åŸã«å®è¡ãããããã«ã¹ã±ãžã¥ãŒã«ãããããšã§ãã
ã³ãŒãã£ã³ã°ã«é²ã¿ãŸããããéåæã¿ã¹ã¯ãå®è¡ããåã«åŸ
æ©ããæéãç§åäœã§è¡šãindex3.html
æ°ãããã£ãŒã«ãã䜿çšããŠãã³ãã¬ãŒããäœæã"Duration"
ãŸãã
<!DOCTYPE html>
<html>
<head>
<title>Synchronicity versus Asynchronicity</title>
<link rel="stylesheet" href="{{url_for('static',filename='css/materialize.min.css')}}">
<script src="{{ url_for('static',filename='js/jquery.min.js') }}"></script>
<script src="{{ url_for('static',filename='js/socket.io.js') }}"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body class="container">
<div class="row">
<h5>Click to start a post scheduled ansycnhronous task with automatic feedback.</h5>
</div>
<div class="card-panel">
<form method='post' id="runTaskForm" action="/runPSATask">
<div>
<input id="duration" name="duration" placeholder="Enter duration in seconds. for example: 30" type="text">
<label for="duration">Duration</label>
</div>
<button style="height:50px;width:600px" type="submit" id="runTask">Run A Post Scheduled Asynchronous Task With Automatic Feedback</button>
</form>
</div>
<div class="row">
<div id="Messages" class="red-text" style="width:800px; height:400px; overflow-y:scroll;"></div>
</div>
<script>
$(document).ready(function() {
var namespace = '/runPSATask';
var url = 'http://' + document.domain + ':' + location.port + namespace;
var socket = io.connect(url);
socket.on('connect', function() {
socket.emit('join_room');
});
socket.on('msg', function(data) {
$("#Messages").prepend('<li>' + data.msg + '</li>');
});
socket.on('status', function(data) {
////alert('socket on status ='+ data.msg);
if (data.msg == 'End') {
$("#runTask").attr("disabled", false);
};
});
});
</script>
<script>
$("#runTask").click(function(e) {
$("#runTask").attr("disabled", true);
$("#Messages").empty();
$.ajax({
type: "Post",
url: '/runPSATask',
data: $("#runTaskForm").serialize(),
success: function(data) {
$("#Messages").empty();
$("#Messages").prepend('<li>The Task ' + data.taskid + ' has been submitted and will execute in ' + data.duration + ' seconds. </li>');
}
});
e.preventDefault();
console.log('runPSATask complete');
});
</script>
</body>
</html>
次ã«ãapp_async3.py
ãã®ã·ããªãªã®Flaskã¢ããªã¯æ¬¡ã®ãšããã§ãã
#app_async3.py
from gevent import monkey
monkey.patch_all()
from flask import render_template, jsonify, session, request
from random import randint
import uuid
import tasks
from init import app, socketio
from flask_socketio import join_room
@app.route("/",methods=['GET'])
def index():
# create a unique session ID
if 'uid' not in session:
sid = str(uuid.uuid4())
session['uid'] = sid
print("Session ID stored =", sid)
return render_template('index3.html')
#Run a Post Scheduled Asynchronous Task With Automatic Feedback
@app.route("/runPSATask",methods=['POST'])
def long_async_sch_task():
print("Running", "/runPSATask")
# Generate a random number between MIN_WAIT_TIME and MAX_WAIT_TIME
n = randint(app.config['MIN_WAIT_TIME'], app.config['MAX_WAIT_TIME'])
data = {}
data['sessionid'] = str(session['uid'])
data['waittime'] = n
data['namespase'] = '/runPSATask'
data['duration'] = int(request.form['duration'])
#Countdown represents the duration to wait in seconds before running the task
task = tasks.long_async_sch_task.apply_async(args=[data],countdown=data['duration'])
return jsonify({ 'taskid':task.id
,'sessionid':data['sessionid']
,'waittime': data['waittime']
,'namespace':data['namespase']
,'duration':data['duration']
})
@socketio.on('connect', namespace='/runPSATask')
def socket_connect():
print('Client Connected To NameSpace /runPSATask - ',request.sid)
@socketio.on('disconnect', namespace='/runPSATask')
def socket_connect():
print('Client disconnected From NameSpace /runPSATask - ',request.sid)
@socketio.on('join_room', namespace='/runPSATask')
def on_room():
room = str(session['uid'])
print(f"Socket joining room {room}")
join_room(room)
@socketio.on_error_default
def error_handler(e):
print(f"socket error: {e}, {str(request.event)}")
if __name__ == "__main__":
socketio.run(app,debug=True)
ä»ålong_async_sch_task()
ããã¿ã¹ã¯ã¡ãœããã䜿çšããŠããããšã«æ³šæããŠãã ããtasks.py
ã
app_async3.py
以åãšåãããã«å®è¡ãããã©ãŠã¶ãéããŸãã
æéïŒã€ãŸã10ïŒãå
¥åãããã¿ã³ãæŒããŠãã¹ã±ãžã¥ãŒã«åŸã®éåæã¿ã¹ã¯ãäœæããŸããäœæããããšãã¿ã¹ã¯ã®è©³çްã瀺ãã¡ãã»ãŒãžã[ã¡ãã»ãŒãž]ããã¯ã¹ã«è¡šç€ºãããŸãã
æéãã£ãŒã«ãã§æå®ããæéåŸ ã€å¿ èŠããããŸããã¿ã¹ã¯ãå®è¡ãããŠããããšãããããŸãã
ãŸãã
celery.logs
ãã°ãã¡ã€ã«ã«å«ãŸããŠããã»ããªã¯ãŒã«ãŒã®ãã°ã埩å
ãããšãã¿ã¹ã¯ã®ã©ã€ããµã€ã¯ã«ã«æ°ä»ãã§ãããã
ã»ããªã¿ã¹ã¯ãããé©åã«ç£èŠããããã«ãã»ã㪠ã¯ã©ã¹ã¿ãŒãç£èŠããã³ç®¡çããããã®WebããŒã¹ã®ããŒã«ã§ããFlowerãã€ã³ã¹ããŒã«ã§ããŸãã
泚æïŒãã©ã¯ãŒã©ã€ãã©ãªã¯ã®äžéšã§ããrequirements.txt
ã
è±ã䜿çšããŠã»ããªã®ã¿ã¹ã¯ã衚瀺ããã«ã¯ãæ¬¡ã®æé ã«åŸã£ãŠãã ããã
$ async-venv\Scripts\flower.exe worker -A tasks --port=5555
Linux / MacOSã®å ŽåïŒ
$ async-venv/bin/flower worker -A tasks --port=5555
ã³ã³ãœãŒã«ã«æ¬¡ã®æ å ±ã衚瀺ãããŸãã
ã¢ããªã«æ»ã£ãŠã¿ã¹ã¯ãå®è¡ãããã©ãŠã¶ãéããŠ
http://localhost:5555
[ã¿ã¹ã¯]ã¿ãã«ç§»åããŸãã
ã¿ã¹ã¯ãå®äºãããšããã©ã¯ãŒããã·ã¥ããŒãã«æ¬¡ã®ããã«è¡šç€ºãããŸãã
ãã®èšäºããCeleryã®å©ããåããŠåæããã³éåæãªã¯ãšã¹ãã®æŠå¿µçãªåºç€ãåŸãã®ã«åœ¹ç«ã€ããšãé¡ã£ãŠããŸããåæèŠæ±ã¯é ããªãå¯èœæ§ããããéåæèŠæ±ã¯è¿ éã«å®è¡ãããŸãããããããã·ããªãªã«é©åãªæ¹æ³ãèªèããããšãéèŠã§ããæã«ã¯ã圌ãã¯äžç·ã«åãããšãããããŸãã
ãªã³ã¯: https://www.thepythoncode.com/article/async-tasks-with-celery-redis-and-flask-in-python
1599119110
Next js Tutorial For Beginners is the todayâs topic. It is no secret that creating single-page applications can be immensely challenging these days. But with the help of some libraries, frameworks, and tools, it is effortless nowadays. React.js is the common frontend libraries among the Front-end developers. Its virtual dom theory makes React faster and gives us the better application performance. Now, one problem is that Single Page Applications are not at all SEO friendly because it is rendered on the Client side and not Server side . So when the Search Engine crawlers try to send a request, they cannot get our meta content or description and not even the main content. Search Engines do not care about how your app is architected or whatever ideology was used to adjust and fetch the right material. Their bots are not as smart as using your apps as a real user would. All they care about is that once they send their spiders to crawl and index your site, whatever the server provides on the first request is what gets indexed. In our case, all they get is our div tag with an id and bundled JS file, and we can not index our website correctly. So some how, we need a SSR to tackle this problem and in React js, Next.js is the perfect solution.
#js #react.js #next.js