영상 생성 기능이 약 3분 이상 소요되기 때문에 진행 상황을 클라이언트에게 공유하고자 응답 스트리밍을 구현하고자 한다. 일단 사용하던 Lambda에 있는 기능인 응답 스트리밍을 사용하고자 했는데 청크가 뭉쳐서 받아져오는 문제가 있어 일단 보류.... 그 다음 생각해낸 것이 SSE이다.
Server Sent Events
요청을 보낸 후 일정 시간동안 연결을 유지한 후, 서버에서 message를 emit하는 방식이다.
연결이 끊기기 전까지는 Client가 추가로 요청할 필요가 없기 때문에 메시지가 쌓일 수록 0.5RTT만큼의 시간이 절약된다고 생각할 수 있다. 이후 서버에서 message를 전송하면 클라이언트는 WebSocket 통신과 유사한 방식으로 메시지를 받을 수 있으나, 클라이언트에서 서버로 메시지를 전송할 순 없다.
우리 프로젝트는
1. 클라이언트에서 메세지를 보낼 필요가 없고,
2. 특정 시간 동안만 연결을 유지하고 작업이 완료되면 연결을 해제하면 되고,
3. 연결이 유지되 기간 동안 지속적으로 메세지를 전달해야하기 때문에,
SSE가 적합하다고 생각했다.
참고한 블로그
더 자세한 내용을 포함하고 있으니 꼭 참고하자
https://velog.io/@reljacer/SSE%EC%97%90-%EA%B4%80%ED%95%98%EC%97%AC
SSE 연결 시 고려해야 할 것들
Response 헤더 설정
- Content-Type : text/event-stream
- 표준으로 지정되어 있다.
text형식의 간단한 stream으로 구성되어 있으며, 각 데이터는 \n\n로 구분된다.
- 표준으로 지정되어 있다.
- Connection : keep-alive
- SSE의 persistent connection을 위해 keep-alive로 지정해야 한다.
- Transfer-Encoding : chunked
- SSE는 동적으로 생성된 컨텐츠를 스트리밍하기 때문에 서버에서 미리 본문의 길이를 알 수 없다. 따라서 청크단위로 끊어서 보낸다.
- charset : UTF-8
- event-stream은 binary로 해석될 수 없으며, utf-8방식으로 인코딩이 되어야 한다.
SSE 데이터 구조
event: <client에서 처리할 이벤트 명>
data: <메시지 내용>
\n\n
간단한 테스트 코드 구현
//handler: ./src/index.handler
import controller from './controller.js';
import service from './service.js';
const OK = 200;
const CREATED = 201;
const UNAUTHORIZED = 401;
const BAD_REQUEST = 400;
const NOT_FOUND = 404;
const INTERNAL_SERVER_ERROR = 500;
export const handler = awslambda.streamifyResponse(async (event, responseStream, _context) => {
const metadata = {
statusCode: 200,
headers: {
"Content-Type": "text/event-stream",
"Connection": "keep-alive",
"charset": "UTF-8",
"Transfer-Encoding": "chunked",
"X-Accel-Buffering": "no"
}
};
// Assign to the responseStream parameter to prevent accidental reuse of the non-wrapped stream.
responseStream = awslambda.HttpResponseStream.from(responseStream, metadata);
responseStream.write("data: Streaming with Helper \n\n");
await new Promise(r => setTimeout(r, 3000));
responseStream.write("data: Hello 0 \n\n");
await new Promise(r => setTimeout(r, 3000));
responseStream.write("data: Hello 1 \n\n");
await new Promise(r => setTimeout(r, 3000));
responseStream.write("data: Hello 3 \n\n");
await new Promise(r => setTimeout(r, 3000));
responseStream.write("data: Hello 5 \n\n");
await new Promise(r => setTimeout(r, 3000));
responseStream.write("data: Hello 7 \n\n");
await new Promise(r => setTimeout(r, 3000));
responseStream.end();
//await responseStream.finished();
}
);
이렇게 수정해도 청크가 뭉쳐서 오는 이슈는 아직도 존재했다. 아마 Lambda를 사용하기 때문에 이렇 문제가 SSE를 사용해도 그대로 발생하는 것 같다. 그리고 프론트에서 화면 이동을 하면 이 연결이 끊긴다고 말해서 결국은 웹소켓을 통한 연결을 시도해보기로 했다.
'Graduation Project' 카테고리의 다른 글
응답 스트리밍(1) - AWS Lambda 응답 스트리밍 (1) | 2024.07.22 |
---|---|
프롬프트 엔지니어링 (0) | 2024.07.08 |
S3 + CloudFront 비디오 스트리밍 (0) | 2024.07.03 |
[Error 😥] Serverless Framework 사용 도전기 (0) | 2024.07.02 |
AWS APIgateway+ 응답 HTTP status 변경하기 (0) | 2024.06.28 |