Пользовательская лямбда-функция AWS CodePipeline выполняется вечно и никогда не возвращается

#amazon-web-services #aws-lambda #boto3 #aws-codepipeline #aws-codestar

#amazon-веб-сервисы #aws-lambda #boto3 #aws-codepipeline #aws-codestar

Вопрос:

У меня есть простой AWS CodePipeline со стандартными этапами конвейера «Исходный код» -> «Сборка» -> «Развертывание», которые работают нормально, и я пытаюсь добавить свой собственный конечный этап конвейера, который представляет собой единую функцию AWS Lambda. Проблема в том, что моя последняя пользовательская лямбда-функция выполняется несколько раз и после очень долгого времени выдает ошибки со следующим сообщением:

введите описание изображения здесь

Пожалуйста, смотрите прикрепленный скриншот для всего конвейера:

введите описание изображения здесь

Когда конвейер достигает этого последнего шага, он очень долго вращается со статусом «Синий (выполняется)», прежде чем выдать ошибку, как показано здесь:

введите описание изображения здесь

Вот мой код лямбда-функции:

 from __future__ import print_function
import hashlib
import time
import os
import boto3
import json
from botocore.exceptions import ClientError

def lambda_handler(event, context):
    
    # Test
    AWS_ACCESS_KEY = ASDF1234
    AWS_SECRET_KEY = ASDF1234
    SQS_TESTING_OUTPUT_STATUS_QUEUE_NAME = 'TestingOutputQueue'

    # Get the code pipeline
    code_pipeline = boto3.client('codepipeline')
    
    # Get the job_id
    for key, value in event.items():
        print(key,value)
    job_id = event['CodePipeline.job']['id']
    DATA = json.dumps(event)
    
    # Create a connection the SQS Notification service
    sqs_resource_connection = boto3.resource(
        'sqs',
        aws_access_key_id = AWS_ACCESS_KEY,
        aws_secret_access_key = AWS_SECRET_KEY,
        region_name = 'us-west-2'
    )
    
    # Get the queue handle
    print("Waiting for notification from AWS ...")
    queue = sqs_resource_connection.get_queue_by_name(QueueName = SQS_TESTING_OUTPUT_STATUS_QUEUE_NAME)
    messageContent = ""
    cnt = 1
        
    # Replace sender@example.com with your "From" address.
    # This address must be verified with Amazon SES.
    SENDER = ME
    
    # Replace recipient@example.com with a "To" address. If your account
    # is still in the sandbox, this address must be verified.
    RECIPIENTS = [YOU]
    
    # If necessary, replace us-west-2 with the AWS Region you're using for Amazon SES.
    AWS_REGION = "us-east-1"
    
    # The subject line for the email.
    SUBJECT = "Test Case Results"
    
    # The email body for recipients with non-HTML email clients.
    BODY_TEXT = ("Test Case Results Were ...")
    
    # The HTML body of the email.
    BODY_HTML = """<html>
    <head></head>
    <body>
      <h1>Amazon SES Test (SDK for Python)</h1>
      <p>%s</p>
    </body>
    </html>
                """%(DATA)
    
    # The character encoding for the email.
    CHARSET = "UTF-8"
    
    # Create a new SES resource and specify a region.
    client = boto3.client('ses', region_name=AWS_REGION)
    
    # Try to send the email.
    try:
        # Provide the contents of the email.
        response = client.send_email(
            Destination={
                'ToAddresses': RECIPIENTS,
            },
            Message={
                'Body': {
                    'Html': {
                        'Charset': CHARSET,
                        'Data': BODY_HTML,
                    },
                    'Text': {
                        'Charset': CHARSET,
                        'Data': BODY_TEXT,
                    },
                },
                'Subject': {
                    'Charset': CHARSET,
                    'Data': SUBJECT,
                },
            },
            Source=SENDER,
            # If you are not using a configuration set, comment or delete the
            # following line
            #ConfigurationSetName=CONFIGURATION_SET,
        )
    # Display an error if something goes wrong.
    except ClientError as e:
        code_pipeline.put_third_party_job_failure_result(jobId=job_id, failureDetails={'message': message, 'type': 'JobFailed'})
        code_pipeline.put_job_failure_result(jobId=job_id, failureDetails={'message': message, 'type': 'JobFailed'})      
        print(e.response['Error']['Message'])
    else:
        code_pipeline.put_third_party_job_success_result(jobId=job_id)
        code_pipeline.put_job_success_result(jobId=job_id)
        print("Email sent! Message ID:"),
        print(response['MessageId'])
        
    print('Function complete.')   
    return "Complete."
        
  

Как я могу заставить лямбду сработать один раз и вернуться, чтобы конвейер мог завершиться должным образом.

Комментарии:

1. По какой-то причине я не видел вызова вашего кода put_job_success_result при первом чтении вашего Q. В любом случае, вам не нужно вызывать put_third_party_job_success_result . Попробуйте обойтись без нее и добавьте несколько отладочных отпечатков, чтобы проверить, зависает ли она и где.

2. Привет @jweyrich — спасибо за ответ и комментарий. Я пробовал без вызовов «third_party_job», но это по-прежнему не удается. Должно быть, мне чего-то не хватает, но я пока не могу понять этого. Я пробовал различные комбинации «put_third_party_job_success_result», «put_job_success_result» и даже «return». Есть еще идеи? Спасибо.

3. Когда она выполняется бесконечно, она отправляет несколько электронных писем — таким образом, она действует так, как будто лямбда-функция вызывается несколько раз. Это подсказка?

4. Возможно ли put_job_success_result вызвать исключение? Переместите ее внутрь try блока для проверки.

Ответ №1:

Вы упускаете важную интеграцию между вашим Lambda Function сервисом и CodePipeline .

Вы ДОЛЖНЫ уведомить CodePipeline о результате вашего пользовательского шага, независимо от того, был ли он успешным или нет — смотрите Мои примеры ниже.

Сообщение об успешном выполнении:

 function reportSuccess(job_id) {
  var codepipeline = new AWS.CodePipeline();
  var params = {
    jobId: job_id,
  };
  return codepipeline.putJobSuccessResult(params).promise();
}
  

Ошибка сообщения:

 function reportFailure(job_id, invoke_id, message) {
  var codepipeline = new AWS.CodePipeline();
  var params = {
    failureDetails: {
      message: message,
      type: 'JobFailed',
      externalExecutionId: invoke_id,
    },
    jobId: job_id,
  };
  return codepipeline.putJobFailureResult(params).promise();
}
  

Интеграция была разработана таким образом, потому что может потребоваться интеграция с внешним рабочим заданием, в котором их Lambda запускает этот рабочий процесс (например, процесс утверждения), и этот рабочий затем берет на себя управление и решает, был ли весь шаг успешным или неудачным.