1. 程式人生 > >我的郵箱[email protected]

我的郵箱[email protected]

開始

本文不是針對分析celery或者教學的,只是在學習之餘對自己在專案中使用的總結,董老師知乎上有篇文章寫的非常好,大家可以移步,我也是看了這篇文章瞭解了很多。

如果想直接看專案的直接移步github專案

專案中Celery是使用redis最為代理的,功能主要是:
1. 傳送郵件;
2. 定時更新一些有時效性的資料,判斷是否到期;

配置

官方文件的配置列表在這裡。

下面是專案中的配置,使用的crontab的方式執行週期任務:

# config/settings.py
...
# Celery.
CELERY_BROKER_URL = 'redis://:[email protected]
:6379/0'
# redis作為訊息代理 CELERY_RESULT_BACKEND = CELERY_BROKER_URL # 任務結果儲存在redis CELERY_ACCEPT_CONTENT = ['json'] # 接受的內容型別 CELERY_TASK_SERIALIZER = 'json' # 任務序列化和反序列化使用json CELERY_RESULT_SERIALIZER = 'json' # 同上,結果使用json CELERY_REDIS_MAX_CONNECTIONS = 5 # 允許redis連線池用於發取訊息的連線數 CELERYBEAT_SCHEDULE = { # 任務排程,定期將任務傳送到佇列中
'mark-soon-to-expire-credit-cards': { 'task': 'snakeeyes.blueprints.billing.tasks.mark_old_credit_cards', 'schedule': crontab(hour=0, minute=0) }, 'expire-old-coupons': { 'task': 'snakeeyes.blueprints.billing.tasks.expire_old_coupons', 'schedule': crontab(hour=0
, minute=1) }, }

docker-compose.yml配置

celery:
  build: .  # 指定Dockerfile檔案所在位置
  command: celery worker -B -l info -A snakeeyes.blueprints.contact.tasks  # 執行celery worker,-A是指定應用,-l是指定訊息級別為info,-B啟動Beat定時任務
  env_file:  # 環境配置
    - '.env'
  volumes:  # 掛載路徑
    - '.:/snakeeyes'

app.py中celery的建構函式

這個建構函式是根據Flask官方配置寫的,目的是增加上下文支援等。

# 為了後續方便管理和修改,單獨將Celery的include引數值放到這裡,這裡就是所有通過Celery排程的任務列表
CELERY_TASK_LIST = [
    'snakeeyes.blueprints.contact.tasks',
    'snakeeyes.blueprints.feedback.tasks',
    'snakeeyes.blueprints.user.tasks',
    'snakeeyes.blueprints.billing.tasks',
]


def create_celery_app(app=None):
    """
    Create a new Celery object and tie together the Celery config to the app's
    config. Wrap all tasks in the context of the application.

    :param app: Flask app
    :return: Celery app
    """
    app = app or create_app()

    celery = Celery(app.import_name, broker=app.config['CELERY_BROKER_URL'],
                    include=CELERY_TASK_LIST)
    celery.conf.update(app.config)
    TaskBase = celery.Task

    class ContextTask(TaskBase):
        abstract = True

        def __call__(self, *args, **kwargs):
            with app.app_context():
                return TaskBase.__call__(self, *args, **kwargs)

    celery.Task = ContextTask
    return celery

tasks

專案中的任務一般都放在各個藍圖的tasks.py中。比如重置密碼的郵件:

celery = create_celery_app()  # 構造celery例項


@celery.task()  # 用過裝飾器告訴celery任務函式
def deliver_password_reset_email(user_id, reset_token):
    """
    Send a reset password e-mail to a user.

    :param user_id: The user id
    :type user_id: int
    :param reset_token: The reset token
    :type reset_token: str
    :return: None if a user was not found
    """
    user = User.query.get(user_id)

    if user is None:
        return

    ctx = {'user': user, 'reset_token': reset_token}

    send_template_message(subject='Password reset from Snake Eyes',
                          recipients=[user.email],
                          template='user/mail/password_reset', ctx=ctx)  # 實際渲染郵件和傳送郵件的函式

    return None

實際應用是在User model下面一個重置密碼的類方法:

    @classmethod
    def initialize_password_reset(cls, identity):
        """
        Generate a token to reset the password for a specific user.

        :param identity: User e-mail address or username
        :type identity: str
        :return: User instance
        """
        u = User.find_by_identity(identity)  # 查詢使用者
        reset_token = u.serialize_token()  # 序列化token

        # This prevents circular imports.
        from snakeeyes.blueprints.user.tasks import (
            deliver_password_reset_email)
        deliver_password_reset_email.delay(u.id, reset_token)  # 通過呼叫delay將任務傳送

        return u

在views裡面使用者觸發是通過提交一個密碼重置的表單,如果使用者在網頁上點選了重置密碼就會提交這個表單,觸發後面的操作,並通過flash告知使用者資訊,將使用者重定向到user.login這個view下面:

@user.route('/account/begin_password_reset', methods=['GET', 'POST'])
@anonymous_required()
def begin_password_reset():
    form = BeginPasswordResetForm()

    if form.validate_on_submit():
        u = User.initialize_password_reset(request.form.get('identity'))

        flash('An email has been sent to {0}.'.format(u.email), 'success')
        return redirect(url_for('user.login'))

    return render_template('user/begin_password_reset.html', form=form)

下面是郵件中通過jinja2渲染的連結:

{{ url_for('user.password_reset', reset_token=reset_token, _external=True) }}

可以看到連結會將使用者定位到user.password_reset這個view。我們再看看這個view是怎麼操作的。
可以看到初次get請求會得到password_reset.html,如果在這個頁面有提交重置密碼的表單的話,會用表單的資料替換掉對應User的資料並儲存,達到修改密碼的效果。

@user.route('/account/password_reset', methods=['GET', 'POST'])
@anonymous_required()
def password_reset():
    form = PasswordResetForm(reset_token=request.args.get('reset_token'))

    if form.validate_on_submit():
        u = User.deserialize_token(request.form.get('reset_token'))

        if u is None:
            flash('Your reset token has expired or was tampered with.',
                  'error')
            return redirect(url_for('user.begin_password_reset'))

        form.populate_obj(u)
        u.password = User.encrypt_password(request.form.get('password'))
        u.save()

        if login_user(u):
            flash('Your password has been reset.', 'success')
            return redirect(url_for('user.settings'))

    return render_template('user/password_reset.html', form=form)

定時任務

上面的task說的是使用者觸發的操作,將任務推送到佇列中。定時任務我們已經在配置中設定好了(有關crontab的引數詳見這裡):

CELERYBEAT_SCHEDULE = {  # 任務排程,定期將任務傳送到佇列中 
    'mark-soon-to-expire-credit-cards': {  # 名稱
        'task': 'snakeeyes.blueprints.billing.tasks.mark_old_credit_cards',  # 任務
        'schedule': crontab(hour=0, minute=0)  # 每天凌晨執行
    },
    'expire-old-coupons': {
        'task': 'snakeeyes.blueprints.billing.tasks.expire_old_coupons',
        'schedule': crontab(hour=0, minute=1)  # 每天零點一分執行
    },
}

這裡說明第一個任務,每天凌晨檢查並標記即將到期的信用卡。根據任務路徑可以看到程式碼片段:

@celery.task()
def mark_old_credit_cards():
    """
    Mark credit cards that are going to expire soon or have expired.

    :return: Result of updating the records
    """
    return CreditCard.mark_old_credit_cards()  # 呼叫的是CreditCard這個類下面的一個類方法並返回結果

可以看到和生產任務的方式類似,只是在配置是將其放入CELERYBEAT_SCHEDULE這個字典。

相關推薦

郵箱<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="d9ebefb1acb0adb8b0b5b8b7be99beb4b8b0b5f7bab6b4">[email&#160;protected]a

開始 本文不是針對分析celery或者教學的,只是在學習之餘對自己在專案中使用的總結,董老師知乎上有篇文章寫的非常好,大家可以移步,我也是看了這篇文章瞭解了很多。 如果想直接看專案的直接移步github專案。 專案中Celery是使用redis最為代理的,

郵箱<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="d2e0e4baa7bba6b3bbbeb3bcb592b5bfb3bbbefcb1bdbf">[email&#160;protected]a

000 git區域的關係 幾個專用名詞的譯名如下。 Workspace:工作區 Index / Stage:暫存區 Repository:倉庫區(或本地倉庫) Remote:遠端倉庫 001 初始化一個倉庫 git init

郵箱<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="e9dbdf819c809d88808588878ea98e84888085c78a8684">[email&#160;protected]a

之前用docker時候速度感覺還能接受,但是最近docker-compose up –build 的時候pull速度簡直不能忍,於是查了下國內的加速方法,這個是cn docker的原文,中國官方映象加速。 我是用的永久更改,新增映象路徑到配置檔案: sudo

正則表示式驗證郵箱地址<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="a0c1c2c3919392e09196938ec3cfcd">[email&#160;protected]a>

通常我們在註冊郵箱帳號時,怎麼來驗證郵箱是否合法呢? 比如我們要註冊一個163郵箱,首先要校驗是否合法,其次才是是否已被使用,需要符合以下的格式: 6~18個字元, 可使用字母、數字、下劃線, 需以字母開頭。 我們可以定義一個正則表示式:^[a-zA-Z]\w{5,17}@163.c

郵箱:<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="d3e2ebe0e7e2e0e2e7e1e493a2a2fdb0bcbe">[email&#160;protected]a>

10/16 這個星期日就要體側了,這個1000m感覺比ccpc還要難應付。所以這幾天晚上的健身時間就變成了操場上的跑步時間。為什麼強調操場?因為我在健身房的跑步機上可以1000跑的速度在操場上只能怕跑800。風阻太大了! 10/17 中午吃飯的時候無聊就看了會演

郵箱:<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="eedfd6dddadfdddfdadcd9ae9f9fc08d8183">[email&#160;protected]a>

TSP TSP問題非常經典,(旅行商問題)是指旅行家要旅行n個城市,要求各個城市經歷且僅經歷一次然後回到出發城市,並要求所走的路程最短。 如圖,從0開始,把1,2,3都走一遍然後回到0,求最短路徑。 方法有很多 暴力法:城市順序全排列,找到最短距離

郵箱:<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="2f1e171c1b1e1c1e1b1d186f5e5e014c4042">[email&#160;protected]a>

#include<stdio.h> #include<string.h> #define D long long #define N 109 #define MOD ((int)1e9+7) struct matrix{ int

郵箱:<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="fccdc4cfc8cdcfcdc8cecbbc8d8dd29f9391">[email&#160;protected]a>

本來寫了很多的,一不小心就刪掉了,哎。懶得重寫了 所有公式要求a與m互質 費馬小定理: :am≡a(mod)ma^m≡a(mod)mam≡a(mod)m , am−1≡1(mod&ThickSpace;m)a^{m-1}≡1(mod \;m)am−1

郵箱:<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="7e4f464d4a4f4d4f4a4c493e0f0f501d1113">[email&#160;protected]a>

題意: 給出一個矩陣,求全1子矩陣的最大面積 解析: 開局的處理方式和最大求和子矩陣類似,壓縮處理。 預處理h[i][j],表示第i行第j列往上(行數遞減方向)可以接上的全1串的最長長度,然後處理第一行到第i行的ans時,就可以看成處理h[i]一行了

【學峰的學習筆記】歡迎交流!郵箱是<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="81f8e0efe6e2e9e0eeb0b8b9b6b1b5b0b5c1b0b7b2afe2eeec">[email&#

歡迎交流!郵箱是[email protected] 所有的部落格的pdf檔案版本都在網盤中可以下載: http://yunpan.cn/cdnAh7bcZjTgk 訪問密碼 d34f...

郵箱:<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="0938313a3d383a383d3b3e497878276a6664">[email&#160;protected]a>

題意: 一些村莊被建立在一條筆直的高速公路邊上,我們用一條座標軸來描述這條高速公路,每一個村莊的座標都是整數,沒有兩個村莊座標相同。兩個村莊間的距離,定義為它們的座標值差的絕對值。我們需要在一些村莊建立郵局——當然,並不是每一個村莊都必須建立郵局,郵局必須

郵箱:<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="1829202b2c292b292c2a2f586969367b7775">[email&#160;protected]a>

其實我線性代數考試每次都99,100的,可惜好久不學都快忘了。 沒想到acm居然要用到,早知道不扔筆記本了QAQ #define A(n,m) n行m列的行列式A #define A[n][m] 行列式A的第n行第m列的元素 #define

郵箱:<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="43727b70777270727771740332326d202c2e">[email&#160;protected]a>

BOLG 群的定義 設G為一個元素的集合,稱G內的元素為元,*為針對G這個集合的元素的運算,當(G,∗)(G,∗)滿足以下要求的時候,我們稱(G,∗)(G,∗)為群 封閉性:G內的任何兩個元的*運算的結果仍在G內 交換律:a∗(b∗c)=(a∗b)∗

shell腳本中的$# $0 <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="f8dcb8">[email&#160;protected]a> $* $$ $! $?的意義

腳本 $* width 上一個 pre shell int .cn height 轉載自:http://www.cnblogs.com/davygeek/p/5670212.html 今天學寫腳本遇到一些變量不認識,在此做下記錄。 變量 含義 $0 當前腳本的文件

shell中$*與<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="b296f2">[email&#160;protected]a>的區別

劃分 位置 一個 這也 差異 獨立 [email protected] 情況 雙引號 $*所有的位置參數,被作為一個單詞 註意:"$*"必須被""引用 [email protected] 與$*同義,但是每個參數都是一個獨立的""引用字串,這就意味著參數

Spring4.0系列<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="aa9f87eae9c5c4cec3dec3c5c4cbc6">[email&#160;protected]a>

one window 標識 cto ace ted ada bsp 布爾 這篇文章介紹Spring 4的@Conditional註解。在Spring的早期版本你可以通過以下方法來處理條件問題: 3.1之前的版本,使用Spring Expression Langua

Spring高級話題<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="b29ff2f7dcd3d0ded7">[email&#160;protected]a>***註解的工作原理

sso metadata bool logs tcl task ota -c ann 出自:http://blog.csdn.net/qq_26525215 @EnableAspectJAutoProxy @EnableAspectJAutoProxy註解 激活Aspe

<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="297a595b40474e69685c5d465e405b4c4d">[email&#160;protected]a>註解與自動裝配(轉發)

配置 調用方法 support autowired 信息 ann over 反射機制 test 1 配置文件的方法我們編寫spring 框架的代碼時候。一直遵循是這樣一個規則:所有在spring中註入的bean 都建議定義成私有的域變量。並且要配套寫上 get 和 se