質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
LINE Messaging API

LINE Messaging APIは、メッセージの送信・返信ができるAPIです。Web APIを経由しアプリケーションサーバとLINEのAPIでやり取りが可能。複数のメッセージタイプや分かりやすいAPIリファレンスを持ち、グループチャットにも対応しています。

Flask

FlaskはPython用のマイクロフレームワークであり、Werkzeug・Jinja 2・good intentionsをベースにしています。

Heroku

HerokuはHeroku社が開発と運営を行っているPaaSの名称です。RubyやNode.js、Python、そしてJVMベース(Java、Scala、Clojureなど)の複数のプログラミング言語をサポートしている。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Redis

Redisは、オープンソースのkey-valueデータストアで、NoSQLに分類されます。すべてのデータをメモリ上に保存するため、処理が極めて高速です。

Q&A

解決済

1回答

2065閲覧

python heroku H12 error

yuudai

総合スコア65

LINE Messaging API

LINE Messaging APIは、メッセージの送信・返信ができるAPIです。Web APIを経由しアプリケーションサーバとLINEのAPIでやり取りが可能。複数のメッセージタイプや分かりやすいAPIリファレンスを持ち、グループチャットにも対応しています。

Flask

FlaskはPython用のマイクロフレームワークであり、Werkzeug・Jinja 2・good intentionsをベースにしています。

Heroku

HerokuはHeroku社が開発と運営を行っているPaaSの名称です。RubyやNode.js、Python、そしてJVMベース(Java、Scala、Clojureなど)の複数のプログラミング言語をサポートしている。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Redis

Redisは、オープンソースのkey-valueデータストアで、NoSQLに分類されます。すべてのデータをメモリ上に保存するため、処理が極めて高速です。

0グッド

0クリップ

投稿2019/05/17 09:35

編集2019/05/18 06:41

前提・実現したいこと

python heroku flaskを使ってline botを作ろうとしています。しかしheroku openをしてみるとapplication errorが出てしまい、ログを見るとH12 timeoutなどのメッセージがあったのでそれについて調べてみると30秒以内に処理しないといけないらしい。処理が重すぎるとなるらしいです。無限ループとかも原因の一つと書かれている記事を見ました。その対処法がバックグラウンドで処理するといいらしいです。そこでいまはバックグラウンド処理をrqで実装しようとしているのですが、考え方がわからないところが出てきました。私は元々外国為替のチャートのデータを定期的に読み込んで特定のシグナルが出たらそれをLINEに通知するというモノを作ろうとしていたのですが、その読み込みと計算の処理が重いのかなと思いmain.pyとtask.pyの二つのファイルに処理を分けました。task.pyで計算してmain.pyの中にあるmessage1関数を実行したいのですがお互いのモジュールがインポートし合うことはできないのでどうすればいいかわかラナイ状態です。そもそもrqでバックグラウンド処理をすることで解決できるのか確信もありません。説明不足なところがあるかもしれませんが素敵な回答お待ちしています。よろしくお願いします。
あとLINE-APIのようなモノをローカルで実験する方法を知りたいです。そうすればもう少し自分で解決できるようになると思うので。

発生している問題・エラーメッセージ

エラーメッセージ

該当のソースコード

main.py

# import library from flask import Flask, request, abort from linebot import ( LineBotApi, WebhookHandler ) from linebot.exceptions import ( InvalidSignatureError, LineBotApiError ) from linebot.models import ( FollowEvent, MessageEvent, TextMessage, TextSendMessage, ImageMessage, ImageSendMessage, TemplateSendMessage, ButtonsTemplate, PostbackTemplateAction, MessageTemplateAction, URITemplateAction ) import os import time import schedule import datetime from task import perfect_order_USDJPY from rq import Queue from worker import conn # 軽量なウェブアプリケーションフレームワーク:Flask app = Flask(__name__) q = Queue(connection=conn) result = q.enqueue(perfect_order_USDJPY, ) #環境変数からLINE Access Tokenを設定 LINE_CHANNEL_ACCESS_TOKEN = os.environ["LINE_CHANNEL_ACCESS_TOKEN"] #環境変数からLINE Channel Secretを設定 LINE_CHANNEL_SECRET = os.environ["LINE_CHANNEL_SECRET"] line_bot_api = LineBotApi(LINE_CHANNEL_ACCESS_TOKEN) handler = WebhookHandler(LINE_CHANNEL_SECRET) @app.route("/callback", methods=['POST']) def callback(): # get X-Line-Signature header value signature = request.headers['X-Line-Signature'] # get request body as text body = request.get_data(as_text=True) app.logger.info("Request body: " + body) # handle webhook body try: handler.handle(body, signature) except InvalidSignatureError: abort(400) return 'OK' # MessageEvent @handler.add(MessageEvent, message=TextMessage) def handle_message(event): line_bot_api.reply_message( event.reply_token, TextSendMessage(text='暇人か!') ) #perfect order message def message1(): try: line_bot_api.push_message('<to>', TextSendMessage(text="ドル円でパーフェクトオーダーが発生しました。")) except LineBotApiError: # error handle print("Error occurred") if __name__ == "__main__": port = int(os.getenv("PORT", 5000)) app.run(host="0.0.0.0", port=port)

task.py

#import library import pandas as pd import numpy as np from oandapyV20 import API from oandapyV20.exceptions import V20Error from oandapyV20.endpoints.pricing import PricingStream import oandapyV20.endpoints.instruments as instruments import time import schedule import datetime accountID = "アカウントID" access_token = "アクセストークン" def perfect_order_USDJPY(): def get_data(): api = API(access_token=access_token, environment="practice") #15分足2000個 params = { "count": 2000, "granularity": "M15" } #ドル円ローソク足データ取得 r = instruments.InstrumentsCandles(instrument="USD_JPY", params=params) api.request(r) # ストリーミングの最初の1件目のデータを確認 r.response['candles'][0] rate = pd.DataFrame.from_dict({r.response['candles'][i]['time']: r.response['candles'][i]['mid'] for i in range(0,len(r.response['candles'])) for j in r.response['candles'][i]['mid'].keys()}, orient='index', ) rate.index = pd.to_datetime(rate.index) #EMAを求める ema = pd.DataFrame() ema['ema_10'] = rate['c'].ewm(span=10).mean() ema['ema_20'] = rate['c'].ewm(span=20).mean() ema['ema_40'] = rate['c'].ewm(span=40).mean() ema['ema_80'] = rate['c'].ewm(span=80).mean() ema['ema_320'] = rate['c'].ewm(span=320).mean() #計算したデータはseries型なのでデータフレームにする。そうしないとエラーが出るから。 ema_10 = pd.DataFrame(ema['ema_10']).reset_index() ema_20 = pd.DataFrame(ema['ema_20']).reset_index() ema_40 = pd.DataFrame(ema['ema_40']).reset_index() ema_80 = pd.DataFrame(ema['ema_80']).reset_index() ema_320 = pd.DataFrame(ema['ema_320']).reset_index() return ema_10, ema_20, ema_40, ema_80, ema_320 scheduler1 = schedule.Scheduler() scheduler2 = schedule.Scheduler() def perfect_order_classifier(message): ema_10, ema_20, ema_40, ema_80, ema_320 = get_data() #10分前がパーフェクトオーダーじゃない場合今がパーフェクトオーダーかどうか計算する if not ema_10.iat[-2, -1] < ema_20.iat[-2, -1] < ema_40.iat[-2, -1] < ema_80.iat[-2, -1] < ema_320.iat[-2, -1] \ and not ema_10.iat[-2, -1] > ema_20.iat[-2, -1] > ema_40.iat[-2, -1] > ema_80.iat[-2, -1] > ema_320.iat[-2, -1]: #下降トレンド if ema_10.iat[-1, -1] < ema_20.iat[-1, -1] < ema_40.iat[-1, -1] < ema_80.iat[-1, -1] < ema_320.iat[-1, -1]: print("Perfect Order Now") #ここからmessage1関数を呼び出したい #上昇トレンド elif ema_10.iat[-1, -1] > ema_20.iat[-1, -1] > ema_40.iat[-1, -1] > ema_80.iat[-1, -1] > ema_320.iat[-1, -1]: print("Perfect Order Now") #ここからmessage1関数を呼び出したい else: print("Not Perfect Order") else: pass #10分毎にperfect_order_classifierを実行する scheduler1.every(10).minutes.do(perfect_order_classifier, "メッセージを送れ") def timer(): day_of_the_week = ["月","火","水","木","金","土","日"] get_today = datetime.date.today() #今日の日付を取得 weekday = day_of_the_week[get_today.weekday()] #曜日に変換 if weekday == "土" or weekday == "日": pass else: #機能 while True: now = datetime.datetime.now() if now.hour == 23 and now.minute >= 50: break else: scheduler1.run_pending() time.sleep(1) #timer()を毎日0時に実行する scheduler2.every().day.at("00:00").do(timer) while True: scheduler2.run_pending() time.sleep(1)

worker.py

import os import redis from rq import Worker, Queue, Connection listen = ['high', 'default', 'low'] redis_url = os.getenv('REDISTOGO_URL', 'redis://localhost:6379') conn = redis.from_url(redis_url) if __name__ == '__main__': with Connection(conn): worker = Worker(map(Queue, listen)) worker.work()

試したこと

ここに問題に対して試したことを記載してください。

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

自己解決

これを参考にすることで動くようになりました。普通にtask.pyにもlineのライブラリをインポートして、message1をtask.pyに移して微調整するだけでした。それにH12 errorもなくなりました。万歳!!!

投稿2019/05/18 13:22

yuudai

総合スコア65

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問