Robyn is a Super Fast Async Python Web Framework with a Rust runtime.
BSD-2-CLAUSE License
Bot releases are hidden (Show)
Published by sansyrox almost 3 years ago
The latest version of Robyn supports async functions in WebSockets now!
@websocket.on("message")
async def connect():
global i
i+=1
if i==0:
return "Whaaat??"
elif i==1:
return "Whooo??"
elif i==2:
return "*chika* *chika* Slim Shady."
elif i==3:
i= -1
return ""
@websocket.on("close")
async def close():
return "Goodbye world, from ws"
@websocket.on("connect")
async def message():
return "Hello world, from ws"
Async functions execute out of order. i.e. They do not block the actor in order to provide concurrent execution. However, if the order is essential for you while using async functions, try using sync functions for now or wait for a future release :D
Full Changelog: https://github.com/sansyrox/robyn/compare/v0.9.0...v0.10.0
Thanks to @Kludex @awestlake87 @ShadowJonathan @shivaylamba @messense for their help(Issues/PRs) with this release. 😄
Published by sansyrox almost 3 years ago
Full Changelog: https://github.com/sansyrox/robyn/compare/v0.8.0...v0.9.0
Robyn supports WebSockets now.
from robyn import Robyn, WS
app = Robyn(__file__)
websocket = WS(app, "/web_socket")
i = -1
@websocket.on("message")
def connect():
global i
i+=1
if i==0:
return "Whaaat??"
elif i==1:
return "Whooo??"
elif i==2:
i = -1
return "*chika* *chika* Slim Shady."
@websocket.on("close")
def close():
print("Hello world")
return "Hello world, from ws"
@websocket.on("connect")
def message():
print("Hello world")
return "Hello world, from ws"
You can have 3 methods for every web socket:
"message", "close" and "connect" for responding to the message received, connection closed and connection initiated.
Published by sansyrox almost 3 years ago
Full Changelog: https://github.com/sansyrox/robyn/compare/v0.8.0...v0.8.1
app.start(url='127.0.0.1')
no longer defaults to 0.0.0.0
and the defaults are also set to their original value.
Published by sansyrox almost 3 years ago
The latest version of Robyn now scales across multiple cores!!
Full Changelog: https://github.com/sansyrox/robyn/blob/main/CHANGELOG.md#v080-2021-11-10
You can select the number of processes and workers now:
python3 app.py --workers=5 --processes=5
╰─ oha -n 500000 -c 50 http://localhost:5000/ --no-tui ─╯
Summary:
Success rate: 1.0000
Total: 74.1781 secs
Slowest: 0.1318 secs
Fastest: 0.0005 secs
Average: 0.0074 secs
Requests/sec: 6740.5379
Total data: 21.93 MiB
Size/request: 46 B
Size/sec: 302.80 KiB
Response time histogram:
0.002 [49062] |■■■■■■■■■■■■■
0.004 [115710] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.006 [105245] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.008 [72753] |■■■■■■■■■■■■■■■■■■■■
0.010 [54286] |■■■■■■■■■■■■■■■
0.012 [36697] |■■■■■■■■■■
0.014 [22683] |■■■■■■
0.016 [14015] |■■■
0.018 [8920] |■■
0.020 [5815] |■
0.022 [14814] |■■■■
Latency distribution:
10% in 0.0025 secs
25% in 0.0037 secs
50% in 0.0060 secs
75% in 0.0095 secs
90% in 0.0136 secs
95% in 0.0171 secs
99% in 0.0278 secs
Details (average, fastest, slowest):
DNS+dialup: 0.0026 secs, 0.0022 secs, 0.0031 secs
DNS-lookup: 0.0000 secs, 0.0000 secs, 0.0001 secs
Status code distribution:
[200] 500000 responses
╰─ oha -n 500000 -c 50 http://localhost:5000/ --no-tui ─╯
Summary:
Success rate: 1.0000
Total: 101.4573 secs
Slowest: 0.0858 secs
Fastest: 0.0011 secs
Average: 0.0101 secs
Requests/sec: 4928.1797
Total data: 8.95 MiB
Size/request: 18 B
Size/sec: 90.37 KiB
Response time histogram:
0.003 [617] |
0.005 [23214] |■■■
0.008 [151605] |■■■■■■■■■■■■■■■■■■■■■
0.011 [228487] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.013 [55292] |■■■■■■■
0.016 [32058] |■■■■
0.019 [7509] |■
0.021 [747] |
0.024 [153] |
0.027 [52] |
0.029 [266] |
Latency distribution:
10% in 0.0075 secs
25% in 0.0086 secs
50% in 0.0097 secs
75% in 0.0111 secs
90% in 0.0138 secs
95% in 0.0155 secs
99% in 0.0178 secs
Details (average, fastest, slowest):
DNS+dialup: 0.0034 secs, 0.0019 secs, 0.0043 secs
DNS-lookup: 0.0001 secs, 0.0000 secs, 0.0011 secs
Status code distribution:
[200] 500000 responses
It saves around 27 seconds under high strain conditions. The default configs are at 1 worker and 1 process. You can config for whatever works best for you.
Special thanks to @JackThomson2 @messense @awestlake87 for the help with the socket sharing feature! 🥳 ✨
Published by sansyrox almost 3 years ago
This version contains major fixes of the previous version:
example below
@app.get("/jsonify")
async def json_get():
return jsonify({"hello": "world"})
Published by sansyrox about 3 years ago
The latest version of Robyn supports route params!! 🥳
You can now add params in the routes and access them from the request object.
@app.post("/jsonify/:id")
async def json(request):
print(request["params"]["id"])
return jsonify({"hello": "world"})
Published by sansyrox about 3 years ago
This new release contains some major developments.
Test use:
from robyn import Robyn, static_file, jsonify
import asyncio
app = Robyn(__file__)
callCount = 0
@app.get("/")
async def h(request):
print(request)
global callCount
callCount += 1
message = "Called " + str(callCount) + " times"
return message
@app.get("/test")
async def test():
import os
path = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "index.html"))
return static_file(path)
@app.post("/jsonify")
async def json(request):
print(request)
return jsonify({"hello": "world"})
@app.post("/post")
async def postreq(request):
return bytearray(request["body"]).decode("utf-8")
@app.put("/put")
async def putreq(request):
return bytearray(request["body"]).decode("utf-8")
@app.delete("/delete")
async def deletereq(request):
return bytearray(request["body"]).decode("utf-8")
@app.patch("/patch")
async def patchreq(request):
return bytearray(request["body"]).decode("utf-8")
@app.get("/sleep")
async def sleeper():
await asyncio.sleep(5)
return "sleep function"
@app.get("/blocker")
def blocker():
import time
time.sleep(10)
return "blocker function"
if __name__ == "__main__":
app.add_header("server", "robyn")
app.add_directory(route="/test_dir",directory_path="./test_dir/build", index_file="index.html")
app.start(port=5000)
Published by sansyrox about 3 years ago
This release is made up of a few major changes:
Special Thanks to:
pyo3-asyncio
and @ShadowJonathan for the code reviews!Example usage:
from robyn import Robyn, static_file, jsonify
app = Robyn(__file__)
callCount = 0
@app.get("/")
async def h():
global callCount
callCount += 1
message = "Called " + str(callCount) + " times"
return message
@app.get("/test")
async def test():
import os
path = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "index.html"))
return static_file(path)
@app.post("/jsonify")
async def json(request):
return jsonify({"hello": "world"})
@app.post("/post")
async def postreq(request):
return bytearray(request["body"]).decode("utf-8")
@app.put("/put")
async def putreq(request):
return bytearray(request["body"]).decode("utf-8")
@app.delete("/delete")
async def deletereq(request):
return bytearray(request["body"]).decode("utf-8")
@app.patch("/patch")
async def patchreq(request):
return bytearray(request["body"]).decode("utf-8")
@app.get("/sleep")
async def sleeper():
await asyncio.sleep(5)
return "sleep function"
@app.get("/blocker")
def blocker():
import time
time.sleep(10)
return "blocker function"
if __name__ == "__main__":
app.add_header("server", "robyn")
app.add_directory(route="/",directory_path="./test_dir/build", index_file="index.html")
app.start(port=5000)
To enable hot reloading, use the following command:
python3 test.py --dev=true
Thank you for all the support during this release! Without the community, this would not be possible! ❤️ 🔥
Published by sansyrox over 3 years ago
Robyn can now serve static files and serve json response
from robyn import Robyn, static_file, jsonify
import asyncio
app = Robyn()
@app.get("/test")
async def test():
import os
path = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "index.html"))
return static_file(path)
@app.post("/jsonify")
async def json():
return jsonify({"hello": "world"})
Published by sansyrox over 3 years ago
Robyn is now HTTP compliant and supports non blocking sync function.
Can process even 1million request without dropping. 🥳
➜ ~ oha -n 1000000 http://localhost:5000
Summary:
Success rate: 1.0000
Total: 426.8401 secs
Slowest: 0.3269 secs
Fastest: 0.0009 secs
Average: 0.0213 secs
Requests/sec: 2342.7976
Total data: 17.17 MiB
Size/request: 18 B
Size/sec: 41.18 KiB
Response time histogram:
0.006 [82867] |■■■■■■■■■
0.011 [272171] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.017 [56678] |■■■■■■
0.023 [123485] |■■■■■■■■■■■■■■
0.029 [245641] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.034 [136749] |■■■■■■■■■■■■■■■■
0.040 [28463] |■■■
0.046 [19679] |■■
0.052 [17939] |■■
0.057 [7251] |
0.063 [9077] |■
Latency distribution:
10% in 0.0070 secs
25% in 0.0097 secs
50% in 0.0229 secs
75% in 0.0288 secs
90% in 0.0340 secs
95% in 0.0423 secs
99% in 0.0570 secs
Details (average, fastest, slowest):
DNS+dialup: 0.0039 secs, 0.0024 secs, 0.0049 secs
DNS-lookup: 0.0000 secs, 0.0000 secs, 0.0006 secs
Status code distribution:
[200] 1000000 responses
Published by sansyrox over 3 years ago
Robyn now supports non blocking (to some extent) sync functions.
You can now use def fx
if your library is not await
supported.
from robyn import Robyn
import asyncio
app = Robyn()
@app.get("/")
async def h():
print("This is the message from coroutine")
return "not sleep function"
@app.get("/sleep")
async def sleeper():
await asyncio.sleep(5)
return "sleep function"
@app.get("/blocker")
def blocker():
import time
time.sleep(10)
return "blocker function"
app.start()
Published by sansyrox over 3 years ago
In this version , a major chunk of dead code has been removed.
Published by sansyrox over 3 years ago
Robyn now supports non blocking async functions and can be installed from pip
.
You can simply use Pip for installation.
pip install robyn
from robyn import Robyn
app = Robyn()
@app.get("/")
async def h():
return "Hello, world!"
app.start()