[FastAPI] Azure Service Bus와 Function App을 활용한 데이터 전송 (2)

2025. 12. 18. 22:05·FastAPI

아키텍쳐 흐름

 

지난 포스팅 [FastAPI] Azure Service Bus와 Function App을 활용한 데이터 전송 (1) 에서는 Service Bus에 JSON 파일을 전송하면 Azure Functoin App에서 트리거로 감지해 JSON 파일을 FastAPI Server 웹소켓으로 전송하고 해당 내용을 브로드캐스트로 모든 병원 프론트엔드로 전송하는 로직을 구현했습니다. 

 

이번 포스팅에서는 구급대원 프론트엔드에서 들어온 음성 녹음 파일을 FastAPI Server에서 처리하고 그 내용을 Azure Service Bus로 전송함으로써 구급대원 프론트엔드부터 병원 프론트엔드까지 한 번에 가도록 완성을 해보겠습니다. 

 


코드 구현

 

위에서 언급한 내용을 완성하기 위해 services 폴더에 event_publisher.py와 search_hospital.py 코드를 작업해야 합니다. 

 

event_publisher.py

 

먼저 event_publisher.py 코드입니다.

FastAPI(생산자)가 생성한 데이터를 Azure Service Bus로 안전하게 던져주는 핵심 로직입니다.

# services/event_publisher.py
import json
import os
from azure.servicebus import ServiceBusClient, ServiceBusMessage
from dotenv import load_dotenv

load_dotenv()

# .env 또는 환경 변수에서 가져오기
SERVICEBUS_CONN_STR = os.getenv("SERVICEBUS_CONNECTION") # Azure Portal에서 복사한 그 문자열
TOPIC_NAME = "az-patient-event-hub"

def publish_patient_event(patient_data: dict, log_id: int):
    """
    분석된 환자 데이터를 Azure Service Bus Topic으로 발행합니다.
    """
    # 1. 클라이언트 생성
    client = ServiceBusClient.from_connection_string(SERVICEBUS_CONN_STR)
    
    with client:
        # 2. 송신자(Sender) 생성
        sender = client.get_topic_sender(topic_name=TOPIC_NAME)
        
        with sender:
            # 3. 메시지 생성
            # body: 실제 GPT 분석 결과 JSON
            # session_id: 환자별 순서 보장을 위해 log_id 또는 고유 ID 사용
            # application_properties: Azure Function에서 필터링하거나 읽을 메타데이터
            message = ServiceBusMessage(
                body=json.dumps(patient_data, ensure_ascii=False),
                session_id=f"patient-{log_id}", 
                application_properties={
                    "Region": "Seoul",       # 실제 환경에선 동적으로 설정 가능
                    "PatientState": "NEW_EMERGENCY"
                }
            )
            
            # 4. 발행!
            sender.send_messages(message)
            print(f"🚀 [ServiceBus] 메시지 발행 성공: patient-{log_id}")

 

ServiceBusClient, ServiceBusMessage 두 가지가 Azure Service Bus와 대화하기 위한 공식 라이브러리들입니다.

 

import는 라이브러리 전체를 from ~ import 는 해당 라이브러리에서 특정부분만 들고옵니다. 예를 들어 azure.servicebus 안에 ServiceBusClient, ServiceBusMessage 두 가지들고 옵니다. 

import json
import os
from azure.servicebus import ServiceBusClient, ServiceBusMessage
from dotenv import load_dotenv

load_dotenv()

 

Azure Portal에서 가져온 "연결 문자열"과 데이터를 던질 구체적인 Topic 이름입니다.

SERVICEBUS_CONN_STR = os.getenv("SERVICEBUS_CONNECTION")
TOPIC_NAME = "az-patient-event-hub"

 

 

서비스 버스와의 전체 연결 통로를 엽니다. 아직 메시지를 보낸 건 아니고, 전화기를 들고 번호를 누른 상태와 같습니다.

앞에서 import한 ServiceBusClient와 그 인자로 연결 문자열을 줍니다.

def publish_patient_event(patient_data: dict, log_id: int):
    client = ServiceBusClient.from_connection_string(SERVICEBUS_CONN_STR)

 

통신이 끝나면 자동으로 연결을 닫아주는 역할을 합니다.

여기서 사용한 client는 ServiceBusClient 클래스를 보고 만든 개체이고 sender는 특정 Topic(az-patient-event-hub)으로 메시지를 쏠 수 있는 전용 발사대입니다.

 

여기서 사용한 with는 파이썬의 '예약어(Keyword)' 또는 '구문(Statement)'입니다. 정확한 용어는 컨텍스트 매니저(Context Manager)라고 부릅니다.

with를 쓰면 코드가 끝나거나, 중간에 에러가 터져서 튕겨 나가더라도 파이썬이 알아서 연결을 안전하게 닫아줍니다.

with client:
        sender = client.get_topic_sender(topic_name=TOPIC_NAME)
        with sender:

 

 

다음으로는 ServiceBusMessage 클래스를 사용하여 message 객체를 만듭니다. 

 

body는 실제 내용물입니다. 우리가 원하는 실제 정보가 담겨있습니다. 

session_id는 순서 보장용 번호표입니다. 

application_properties은 소포 겉면에 붙이는 포스트잇입니다. Azure Function이 내용을 다 열어보지 않고도 "어느 지역인지", "어떤 상태인지"를 바로 알 수 있게 해주는 메타데이터입니다.

 

message = ServiceBusMessage(
                body=json.dumps(patient_data, ensure_ascii=False),
                session_id=f"patient-{log_id}", 
                application_properties={
                    "Region": "Seoul",
                    "PatientState": "NEW_EMERGENCY"
                }
            )

 

search_hospital.py

 

먼저 search_hospital.py 코드입니다.

 

이 코드는 FastAPI 서버와 Oracle 데이터베이스 사이의 대화를 담당하는 핵심 로직입니다. 특히 특정 병원의 상세 정보를 주민등록번호(HPID)로 조회하는 기능을 수행합니다. 

# services/search_hospital.py
import oracledb
from database import get_db_connection

def get_hospital_details_by_id(hpid: str):
    """
    HPID를 조건으로 특정 병원의 이름, 좌표, 전화번호를 가져옵니다.
    """
    connection = get_db_connection()
    cursor = connection.cursor()
    
    try:
        # HPID로 특정 병원 1건 조회
        sql = """
            SELECT hospital_nm, x_pos, y_pos, telno, hpid
            FROM HOSPITAL_MASTER
            WHERE hpid = :hpid
        """
        cursor.execute(sql, [hpid])
        row = cursor.fetchone()
        
        if row:
            # 딕셔너리 형태로 변환
            return {
                "hospital_nm": row[0],
                "x_pos": row[1],
                "y_pos": row[2],
                "telno": row[3],
                "hpid": row[4]
            }
        return None
    finally:
        cursor.close()
        connection.close()

 

Python에서 Oracle DB에 접속할 수 있게 해주는 라이브러리을 import 합니다. 

import oracledb
from database import get_db_connection

 

DB와 연결하고 cursor 변수를 사용합니다. 

def get_hospital_details_by_id(hpid: str):
    connection = get_db_connection()
    cursor = connection.cursor()

 

Oracle DB에 쿼리할 내용을 작성합니다. 

:hpid는 바인드 변수로 SQL 문 안에 직접 값을 넣지 않고 cursor가 보내주는 값을 사용합니다. 

sql = """
            SELECT hospital_nm, x_pos, y_pos, telno, hpid
            FROM HOSPITAL_MASTER
            WHERE hpid = :hpid
        """
        cursor.execute(sql, [hpid])

 

쿼리 결과를 fetchone 하여 가져오빈다. 

row = cursor.fetchone()

 

가져온 값을 리턴해줍니다.

if row:
            return {
                "hospital_nm": row[0],
                "x_pos": row[1],
                "y_pos": row[2],
                "telno": row[3],
                "hpid": row[4]
            }

 

여기서는 with 문을 쓰지 않았기 때문에 수동으로 close( ) 사용하여 닫아줍니다. 

finally:
        cursor.close()
        connection.close()

 

여기까지 작성했다면 마지막으로 main.py에 라우터를 정의해주고 서버를 켜줍니다. 


로컬 테스트

 

서버가 정상적으로 작동합니다.

 

다음으로 vscode에서 F5를 눌러 함수를 작동합니다.

 

이번에는 곧바로 postman으로 가서 열어준 포트인 http://0.0.0.0:8000/api/v1/audio 로 오디오 파일을 POST 합니다. 

조금 후에 오디오 파일의 분석이 잘 나옴을 확인할 수 있습니다.

 

 

다음으로 Azure Function에서도 Service Bus 트리거를 작동하고 FastAPI 로 데이터를 잘 전송했음을 확인할 수 있습니다. 

 

 

FastAPI 서버의 로그도 잘 찍혀있습니다. 

 

기존의 로직이었던 DB에 데이터를 적재하는 과정도 잘 동작합니다. 

 

마지막으로 Azure 포털에 접속해 Azure Service Bus에 찍힌 로그를 확인할 수 있습니다. 

 

'FastAPI' 카테고리의 다른 글

[FastAPI] JWT를 이용한 회원가입/로그인 서버 구현  (0) 2025.12.21
[FastAPI] Nginx 사용하기  (0) 2025.12.18
[FastAPI] Azure Service Bus와 Function App을 활용한 데이터 전송 (1)  (0) 2025.12.18
[FastAPI] Naver API를 사용한 거리 및 최단경로 시간 탐색  (0) 2025.12.17
[FastAPI] websocket을 사용한 통신  (0) 2025.12.17
'FastAPI' 카테고리의 다른 글
  • [FastAPI] JWT를 이용한 회원가입/로그인 서버 구현
  • [FastAPI] Nginx 사용하기
  • [FastAPI] Azure Service Bus와 Function App을 활용한 데이터 전송 (1)
  • [FastAPI] Naver API를 사용한 거리 및 최단경로 시간 탐색
David0903
David0903
  • David0903
    별별 코딩
    David0903
  • 전체
    오늘
    어제
    • 전체 (92)
      • Microsoft Azure (33)
      • FastAPI (8)
      • YOLO (4)
      • C++ (27)
      • Deep Learning (12)
      • Business Data Analysis (2)
      • Basic Data Analysis (5)
      • Statistics (1)
      • Data Analysis (0)
      • Computer Science (0)
      • InfoSec (0)
  • 블로그 메뉴

    • 홈
  • 링크

    • 블로그
  • 공지사항

  • 인기 글

  • 태그

    deep learning
    모델
    c++
    경사하강법
    학습셋
    Friend
    call by value
    모델 설계
    데이터 다루기
    테스트셋
    call by reference
    딥러닝
    deep learing
    원-핫 인코딩
    object
    operator overloading
    ROS
    상속
    k겹 교차
    생성자
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
David0903
[FastAPI] Azure Service Bus와 Function App을 활용한 데이터 전송 (2)
상단으로

티스토리툴바