One, foreword

Why use Sanic, see Let your Python fly, (asynchronous/coroutine) family bucket

Without further ado, I’ll talk about Sanic as a normal Web application architecture

Two, get to the point

Basic operation

  1. Install Sanic

pip install sanic

  1. Import Sanic
from sanic import Sanic
app = Sanic(__name__)
Copy the code

Middleware And Listeners

Before service startup

@app.listener('before_server_start')
async def start_connection(app, loop):
    Perform some initialization tasks
    Initialize the Redis connection pool
    await RedisPool.init_redis_conn_pool(loop)
Copy the code

Before the service stops

@app.listener('after_server_stop')
async def start_connection(app, loop):
    Perform some backup, emergency, shutdown tasks
    # For example, close connection pooling
    await RedisPool.close_redis_conn_pool()
    await close_connection(app, loop)
Copy the code

Request middleware

@app.middleware('request')
async def add_tokrn_to_request(request):
    # this method is used for each request and can do some processing for the request
    # For example add token, secret, token
    await session_interface.open(request)
Copy the code

Response middleware

@app.middleware('response')
async def save_session(request, response):
    logger = logging.getLogger('response')
    # Every time the server responds, this method is used to handle exceptions, cookies, logger, etc
    # For example, write cookies and record user logs
    await session_interface.save(request, response)
Copy the code

Blueprint

Something like Flask, which is used to organize applications, which is most of the controllers in our MVC pattern,

  1. First declare a BP
order_bp = Blueprint('orders', url_prefix='v1/api/order')
# url_prefix: define route correction,
For example, if you define a query/ ID route in the current blueprint, then you should access it as v1/ API /order/query/id
Copy the code
  1. Referenced in the main program (main.py)
from controller.order_controller import order_bp
app.blueprint(order_bp)
# so order_bp was registered to sanic, can through the browser visit http://example.com/v1/api/order/query/id
Copy the code
  1. Handle exceptions using blueprints
@bp.exception(NotFound)
def ignore_404(request, exception):
    return text("Yep, I totally found the page: {}".format(request.url))
Copy the code

Routing

# GET specifies the route parameter
@order_bp.route('/delete/<oid:int>', methods=['GET'])
async def delete_order(request, oid):
    result = await OrderModel().del_order_by_id(oid)
    if result:
        return json({'status': 'ok'.'result': result})
    return json({'status': 'fail'.'errmsg': 'Failed to get data'})
Copy the code
# Get Params
@service_bp.route('/message/send', methods=['GET'])
async def send_message(request):
    uuid = request.args['uuid'] [0]
    page = request.args['page'] [0]
    result = await MessageService().send_message_2_user(uuid,page)
    if result:
        return json({'status': 'ok'.'result': result})
    return json({'status': 'fail'.'errmsg': 'Failed to get data'})

    return raw(result)
Copy the code
# Modify price
@order_bp.route('/price/modify', methods=['POST'])
async def price_modify(request):
    order_id = request.json['order_id']
    price = request.json['price']
    postage = request.json['postage']
    show_price = request.json['show_price']
    is_shipping = request.json['is_shipping']
    result = await OrderModel().modify_price(order_id, price, postage, show_price, is_shipping)

    if result:
        return json({'status': 'ok'.'result': result})
    return json({'status': 'fail'.'errmsg': 'Failed to get data'})
Copy the code

Response type

from sanic.response import json
# text
response.text('hello world')
# html
response.html('<p>hello world</p>')
# json
response.json({'hello': 'world'})
# file
response.file('/srv/www/hello.txt')
# stream
response.stream(stream_ctx, content_type='text/plain')
Copy the code

What if I want to run additional tasks after Sanic starts?

app.add_task(notify_server_started())
app.add_task(notify_html_spider())
Copy the code

3. Start Sanic service

if __name__ == "__main__":
    app.add_task(notify_server_started())
    app.add_task(notify_html_spider())
    app.run(host="0.0.0.0", port=settings.PORT, workers=settings.workers, debug=settings.DEBUG, access_log=True)
Copy the code

Some parameters can be passed at startup, others are literal, which is easy to understand. Here we will talk about Workers

Workers accepts type INTEGER, which defaults to 1. Passing in 4 means that Sanic will make four copies for you, creating four processes to run your Sanic App

As shown in figure

Multi-process state, the routing will be automatically assigned, so as to increase the throughput, the number of workers based on their own server performance and decide, if you create too much occupied would happen, just as many process mode, your connection to the database or database connection pool to properly adjust the number of big, can appear otherwise excessive number of connections and rejected the connection

Acceptance speech

Sanic introduction is so much, just a basic introduction, as for other similar functions such as subscription, publication, monitoring and so on, you can go to the Sanic official website to learn and refer to

Next time I will probably work with Sanic to explain the use of asynchronous Redis(AIoredis). The example is going to use a function like order countdown, combined with Redis subscription publishing notification