3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

WebAPIでpythonコードを実行できるシステムを作った話

Last updated at Posted at 2021-09-06

なぜ作ったのか

時々バッチ処理やスレイピングなど長時間動作させたいプログラムを書くことがあります
もちろんローカルで実行すれば良いのですが
重たい処理であったり長い時間実行する必要がある場合、PCに負荷がかかるのを避けるためです

「+そのコードを保存出来る」という機能を実装すれば
AWS Lambda的なサーバーレスコンピューティングサービスが出来るのでは?!と思いました

作りました

作ったもの

WebAPIのBodyにpythonのコードを書いてPOSTするとが実行されて結果が返されます
image.png

技術スタック

  • 言語
    python

  • フレームワーク
    django

  • デプロイ先
    Heroku

コード

Djangoで作っているので、url.pyとview.pyのみ載せます
Djangoに関する情報は探せばいっぱい出てくると思うのでそちらを参照ください

url.py
path('wakeup/',views.wakeup ,name='wakeup'),
path('api-exec/',views.api_exec ,name='api-exec'),
path('api-exec-async/',views.api_exec_async ,name='api-exec-async'),
path('api-exec-async-log/',views.api_exec_async_log ,name='api-exec-async-log'),
view.py
api_exec_async_data = {}

@csrf_exempt
def api_exec(request):
    """
    POSTされたPythonのコードを同期実行します
    """
    try:
        data = {}
        code = request.body.decode('utf-8')
        # exec(code, data)
    except Exception as e:
        print(traceback.format_exc())
        return HttpResponse(traceback.format_exc(), status=400)

    exec(code, data)
    if 'exec_result' in data.keys():
        return HttpResponse(data['exec_result'])
    else:
        return HttpResponse('')

@csrf_exempt
def api_exec_async(request):
    """
    POSTされたPythonのコードを非同期実行します
    """
    try:
        code = request.body.decode('utf-8')
    except Exception as e:
        print(traceback.format_exc())
        return HttpResponse(traceback.format_exc(), status=400)

    t1 = threading.Thread(target=exec, args=([code,api_exec_async_data]))
    t1.start()

    return HttpResponse('OK')

def api_exec_async_log(request):
    """
    非同期実行のログを取得します
    """
    if 'exec_result' in api_exec_async_data.keys():
        return HttpResponse(api_exec_async_data['exec_result'])
    else:
        return HttpResponse('')   

def wakeup(request):
    """
    djangoの起動を維持します
    """    
    return HttpResponse("")

使い方

  • api-exec pythonのコードが同期的に実行され、結果が返ります
  • api_exec_async pythonのコードが非同期的に実行されます
    結果取得は難しいので、DBを用意するなどしてそこにデータを投入するようにします
  • api_exec_async_log 非同期実行時のログを取得します

実際に使ってみる

同期実行 

exec_resultに結果を入れると、レスポンスとして実行結果が返ります
また、printでサーバサイドにログとして出力されます
image.png


非同期実行

exec_resultに結果・ログを入れると「api_exec_async_log」で結果・ログが取得できるようになります
ただ、消滅してしまう可能性もあるため、実行中フラグなどに使用するのが良いと思います
image.png


非同期実行時のログ取得

非同期実行時にexec_resultに入っている値を取得できます
image.png

非同期実行時の実行結果の保存

「非同期実行時は結果の取得が困難なので、DBを用意してデータを投入します」と書きましたが
RealtimeDatabaseのRestApiがおすすめです(コレについては別記事を書くかもしれません・・・?)
何気なく使っていますが、importも使用できます
もちろん、環境に対応するライブラリがあることが条件になります

実行WebAPI(RealtimeDatabaseのRestApiを使用してデータを保存)
image.png

RealtimeDatabaseの中身
image.png

この記事を書いていて思ったこと

pythonコードを実行できるWebAPI
「+そのコードを保存出来る」という機能を実装すれば
AWS Lambda的なサーバーレスコンピューティングサービスが出来るのでは?!と思いました
作れたら、また記事を書こうかと思います

まとめ

外部から入力されたコードがかんたんに実行できるところが
さすが動的言語だなぁと思いました
それくらいですかね・・・?

書き忘れていましたが、Herokuの無料枠では起動から30分なにもアクセスがないとスリープモードに入ります
なので、wakeupというAPIを用意したのですが・・・
重たい処理を動かす際はfor文のなかにwakeupAPIを叩くように工夫する必要があったります

以上です

3
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?