JavaScript 개발자를 위한 Rust: AWS Lambda로 SQS 배치 오류 처리

6733 단어
이 게시물에서 부분 배치 응답을 사용하여 AWS SQS 비교를 향상시킬 것입니다.
The partial batch response은 2021년 11월에 다시 발표되었으며 개발자가 부분적인 오류를 처리하는 데 도움이 됩니다.

미니 시리즈Rust for JavaScript developers의 일부로 다른 부분을 확인할 수 있습니다.
  • Part 1 AWS SQS에 대한 기본 비교를 표시했습니다.
  • Part 2 AWS AppConfig에 대한 기본 비교를 표시했습니다.
  • Part 3 CSV 파일 읽기 처리에 대한 기본 비교를 보여 주었습니다.



  • 지난 몇 년 동안 저는 .NET, JavaScript 및 Rust 간에 여러 번 언어를 전환했으며 한 언어로 습득한 지식을 새로운 언어로 이전할 수 있습니다. 따라서 유사성을 빠르게 선택하려면 정신적으로 매핑해야 합니다.

    Serverless Rust가 작동하는 모습을 보고 싶어하는 친구와 이 작업을 하고 있었기 때문에 이에 대한 짧은 글을 썼습니다.

    기본



    Rust는 예를 들어 다음과 같은 많은 내장 기능을 제공합니다.


    JS



    npm
    뱃짐

    npm 초기화
    화물 초기화

    npm 설치
    화물 설치

    npm 실행 빌드
    화물 빌드

    패키지. json
    Cargo.toml

    패키지 잠금. json
    Cargo.lock

    웹팩
    화물 빌드

    보푸라기
    카고 클리피

    더 예쁘다
    화물 fmt

    문서 생성
    화물 문서

    jest와 같은 테스트 라이브러리
    화물 테스트


    새로운 SAM 기반 서버리스 앱 생성

    sam init --location gh:aws-samples/cookiecutter-aws-sam-rust
    


    아마존 SQS



    이전 챌린지the partial batch response가 발표되었는데, 오류를 처리하고 있었습니다. 처리하는 동안 SQS 레코드 중 하나가 실패한다고 가정하면 메시지의 전체 배치가 실패한 것으로 간주됩니다. 우리 중 많은 사람들이 성공 및 실패 메시지를 추적하고 이 제한을 피하기 위해 프로그래밍 방식으로 처리된 메시지를 삭제했습니다.

    코드가 이것one과 매우 유사하기 때문에 aws sam 템플릿부터 시작하여 필요한 변경 사항만 보고하겠습니다.

    AWSTemplateFormatVersion: 2010-09-09
    Transform: 'AWS::Serverless-2016-10-31'
    Description: Writer Lambda.
    
    ##########################################################################
    #  Global values that are applied to all resources                       #
    ##########################################################################
    Globals:
      Function:
        MemorySize: 1024
        Architectures: ["arm64"]
        Handler: bootstrap
        Runtime: provided.al2
        Timeout: 29
        Layers:
          - !Sub arn:aws:lambda:${AWS::Region}:580247275435:layer:LambdaInsightsExtension-Arm64:1
        Environment:
          Variables:
            RUST_BACKTRACE: 1
            RUST_LOG: info
    
    Resources:
    ##########################################################################
    #   Lambda Function                                                      #
    ##########################################################################
      LambdaFunction:
        Type: AWS::Serverless::Function
        Properties:
          CodeUri: ../build/handler
          Policies:
            - AWSLambdaBasicExecutionRole
          Events:
            MySQSEvent:
              Type: SQS
              Properties:
                Queue: <ARN of the SQS queue>
                BatchSize: 10
                FunctionResponseTypes:
                  - ReportBatchItemFailures
    


    코드는 다음과 같습니다.

    pub async fn execute(client: &aws_sdk_dynamodb::Client, event: LambdaEvent<SqsEvent>,) -> Result<Value, Error> {
        let failed_message: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(Vec::new()));
        let mut tasks = Vec::with_capacity(event.payload.records.len());
        let shared_client = Arc::from(client.clone());
    
        for record in event.payload.records.into_iter() {
            let shared_client = shared_client.clone();
            let message_id = record.message_id.unwrap();
            let failed_message = failed_message.clone();
    
            tasks.push(tokio::spawn(async move {
                if let Some(body) = &record.body {
                    let request = serde_json::from_str::<MyStruct>(&body);
                    if let Ok(request) = request {
                        DoSomething::new()
                          .execute(&shared_client, &request)
                          .map_or_else(|e| {
                            failed_message.lock().unwrap().push(message_id.clone());
                          }, |_| ());
                    } 
                }
            }));
        }
    
        join_all(tasks).await;
    
        let response = BatchItemFailures {
            batch_item_failures: failed_message.lock().unwrap().clone()
                .into_iter()
                .map(|message_id| {
                    return ItemIdentifier {
                        item_identifier: message_id,
                    };
                })
                .collect(),
        };
    
        Ok(serde_json::to_value(response).unwrap())
    }
    


    TypeScript 버전과 크게 다르지 않습니다.

    export const handler = async (event: SQSEvent): Promise<BatchItemFailures> => {
      const failedMessageIds: string[] = [];
      await Promise.all(
        event.Records.map(async (record: SQSRecord) => {
          try {
            //DoSomething(record)
          } catch (error) {
            failedMessageIds.push(record.messageId);
          }
        }),
      );
    
      const batchItemFailures: BatchItemFailures = {
        batchItemFailures: failedMessageIds.map(id => {
          return {
            itemIdentifier: id
          }
        })
      };
    
      return batchItemFailures;
    };
    


    Rust는 더 엄격하며 루프 내에서 tokio::spawn을 사용하기 때문에 failed_message 벡터는 단일 차용 규칙을 위반하기 때문에 외부로 이동되고 더 이상 사용할 수 없으므로 다음을 사용해야 합니다.

     Arc<Mutex<Vec<String>>>
    


    실패에 대해 필터링할 수 있는 join_all 반환 내부에서 SQS 식별자를 설정하는 방법을 찾을 수 없습니다.

    결론



    서버리스 애플리케이션의 Rust 구문은 다른 언어보다 더 어색할 수 있습니다. 여전히 나는 Rust를 매일 사용하지 않고 있으며 더 이상 여분의 main(), unwrap() 또는 Mutex/Arc를 알아채지 못합니다. 그것은 언어의 일부일 뿐이며 지금은 익숙해졌습니다.

    내 목표는 다른 프로그래밍 언어를 사용하고, 기술 세트를 재사용하고, 요구 사항에 따라 더 나은 결과를 얻을 수 있음을 입증하는 것입니다(작업에 가장 적합한 도구 선택). 다른 프로그래밍 언어로 동일한 코드를 작성하면 Rust로 빠르게 이동하는 데 도움이 되며 Rust로 쉽게 마이그레이션하는 데 도움이 되기를 바랍니다.

    좋은 웹페이지 즐겨찾기