fastapi에서 backgroundtask는 다소 무거운 작업을 back ground로 돌릴 때 씁니다. 예를 들자면 이메일을 보내는 시간은 다소 깁니다. 그래서, 그냥 task에 등록만 해서 background에서 돌고 있는 무언가가 처리하게 하고, 204 response를 떨어트리는 식으로 쓰게 됩니다. 매우 무거운 작업은 다른 방식을 고려하는 편이 좋습니다.

 


 main.py 입니다. 천천히 보겠습니다.

 

 write_notification입니다. 다른 건 없고요. ti초동안 sleep를 하게 됩니다. 중간에, 프로세스의 id와 thread id를 찍습니다. 이는 background task가 실행될 때 마다 어떤 것이 달라지는지 trace 하기 위함입니다. async def가 아니라, 그냥 def로 호출하였는데요. 왜 그렇게 호출하였는지는 밑에서 후술하겠습니다.

 

 다음에 get_user입니다. GET /c/{ti}로 호출할 수 있습니다. /docs로 들어가서 swagger로 해당 api를 동시에 여러번 호출해 보겠습니다.

 

 end에 떨어지는 부분을 주목해 주세요. 뒤에 숫자가 다릅니다. 이 말인 즉슨, thread id가 모두 다르다는 것입니다. 이를 그림으로 그려보면 아래와 같습니다.

 

 write_notification 함수는 background_task로 돌았는데, 같은 프로세스에 있는 별개의 thread에서 돌았다. async로 설정하면 어떻게 되는지는 잘 실험해 보실 것이라 믿습니다.

 


 간단하게 BackgroundTasks와 BackgroundTask 부분을 보겠습니다. BackgroundTasks는 list를 하나 들고 있습니다. 이는, task를 모아놓는 역할을 합니다. 다음에, __call__ 함수에서, self.tasks를 모두 돌면서 await task()를 하게 됩니다. 이 과정에서 어떤 부분이 호출될까요?

 

 이 함수가 호출됩니다. async가 아니면, run_in_threadpool. 즉 쓰레드 풀 안에서 task를 돌려버립니다. 

 

 

그림을 그리면 이런 모습입니다. 저는 아무런 옵션도 주지 않았으니, 들어온 순서대로 task가 실행되게 됩니다. 한 쓰레드에 1번, 2번 task가 들어온 경우, 1번이 실행된 후에 2번이 실행됩니다. 이 말인 즉슨, task 1이 실행되다가 예외가 발생해 버린 경우, task 2는 실행되지 못한다는 의미입니다. 정말 그럴까요?

 

 

 task 2개는 위와 같습니다. write_notification은 Exception을 떨어트립니다. 다음에 notification 2는 ti를 출력합니다.

 

 

 write_notification task를 등록한 다음에, write_notification_2를 등록하였습니다.

 

 실행 결과를 볼까요? Exception이 떨어지고 그 다음 ti를 출력하는 task는 실행되지 않았음을 알 수 있습니다.