Исключение AWS lambda ResourceConflictException при развертывании

#amazon-web-services #jenkins #gradle #aws-lambda

#amazon-веб-сервисы #дженкинс #gradle #aws-lambda

Вопрос:

У нас есть несколько функций lambda, и я автоматизировал развертывание кода с помощью плагина gradle-aws-plugin-reboot.

Он отлично работает со всеми лямбда-функциями, кроме одной. В этом конкретном случае я получаю эту ошибку:

 com.amazonaws.services.lambda.model.ResourceConflictException: The operation cannot be performed at this time. An update is in progress for resource: arn:aws:lambda:*redacted*:the-lambda-that-fails (Service: AWSLambda; Status Code: 409; Error Code: ResourceConflictException; Request ID: 8fef505a-587c-4e77-a257-182d6eecadd0; Proxy: null)
 

Однако в этой ошибке есть дополнительное предостережение: Это происходит только в Jenkins. Запуск задачи развертывания с моего локального компьютера работает. Я могу отчасти воспроизвести проблему локально, рассылая развертывания в быстрой последовательности, и в этом случае каждый второй сбой. Что вполне понятно, учитывая сообщение об ошибке.

Интересная особенность этого заключается в том, что, хотя он завершается с той же ошибкой, он не завершается в тот же момент, что и Дженкинс. Когда я делаю это локально, при развертывании среды происходит сбой, в jenkins всегда происходит сбой при развертывании кода. Однако я не уверен, какой из них плагин выполняет первым. Кроме того, он не всегда завершается сбоем в jenkins. В редких случаях даже развертывание этого лямбда-кода завершается успешно. Тем не менее, нет случаев сбоя какого-либо из других.

Я знаю о новой функции лямбда-состояний и о том, что она потенциально может привести к этой ошибке. Однако, поскольку все остальные лямбда-выражения работают, используя один и тот же код как в build.gradle, так и в файле jenkinsfile, кажется маловероятным, что это будет моей проблемой.

Вот как выглядит задача развертывания в gradle:

    register<jp.classmethod.aws.reboot.gradle.lambda.AWSLambdaMigrateFunctionTask>("deploy") {

        // Create the environment variables from the gradle property configuration.
        // users and passwords should be stored in the system properties file, not the projects!
        val (environmentProperties, function) = if (branch == "master") {
            val webcamServicePutterProd: String by project
            val webcamServicePutterProdPwd: String by project
            mapLambdaProperties("deployProd_", webcamServicePutterProd, webcamServicePutterProdPwd) to
                    "lambda-function-name-prod"
        } else {
            val webcamServicePutterDev: String by project
            val webcamServicePutterDevPwd: String by project
            mapLambdaProperties("deployDev_", webcamServicePutterDev, webcamServicePutterDevPwd) to
                    "lambda-function-name-dev"
        }

        val jarFile = File("build/libs").walk().first { it.name.endsWith("-all.jar") }
        functionName = function
        zipFile = jarFile
        handler = "webcam.yellow.sqs.lambda.WebcamWorker::handleRequest"
        publish = true
        environment = environmentProperties
    }

 

Как уже упоминалось, это практически идентично во всех лямбдах, кроме свойств, очевидно. Свойства также не могут быть проблемой, поскольку они одинаковы в моей локальной среде и в jenkins.

Выполнение развертывания в файле jenkins довольно неинтересно. Сначала он загружает jar в S3 для архивирования, затем выполняет задачу gradle для развертывания lambda. Просто чтобы быть уверенным, я попробовал без загрузки S3 на всякий случай, если у этого может быть какое-то неясное соединение, но это тоже не помогло.

         stage('Deploy artifact') {
            when {
                equals expected: 'true', actual: deployArtifact
            }
            steps {
            // archive build on S3
                withAWS() {
                    s3Upload(
                            workingDir: 'build/libs/',
                            includePathPattern: '*-all.jar',
                            bucket: 'yellow-artifacts',
                            path: "webcam-worker-lambda/${artifactFolder}/"
                    )
                }

                // deploy build to lambda
                sh './gradlew deploy'
            }
        }

 

Я потратил часы, просматривая все конфигурации разных лямбд, сравнивая их, ища различия, которые могут быть источником проблемы, но у меня почти нет идей, где проблема может быть обнаружена к настоящему времени. У кого-нибудь есть какие-либо догадки?

Ответ №1:

Я понял это. Вам лучше ничего не держать во рту, потому что это смешно!

По сути, у меня не было никаких вариантов, и я остановился на последнем заметном различии между этим развертыванием и теми, которые работали: размер файла развертываемого jar. Сбой, безусловно, был самым маленьким. Поэтому я раздул его примерно на 60%, чтобы сделать его сопоставимым со всем остальным … и это исправило!

Это звучит нелепо. Вот моя гипотеза о том, что происходит: если загрузка занимает слишком мало времени, лямбде каким-то образом требуется больше времени для изменения своего состояния. Я не уверен, почему это может быть, вы ожидаете, что состояние изменится, когда все будет сделано, а не займет больше времени, если все будет сделано быстрее, верно? Может быть, есть минимальное время для сохранения состояния? Я бы не знал. Однако есть одна вещь, подтверждающая эту гипотезу: развертывание с моего локального компьютера всегда работало. Эта загрузка, естественно, займет больше времени, чем требуется Дженкинсу внутри aws vpc. Итак, эта гипотеза, как бы нелепо это ни звучало, соответствует всем фактам, которые у меня есть.

Возможно, кто-то, лучше разбирающийся в механизмах lambda-internal, может добавить к этому комментарий, объясняющий, как это может произойти…

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

1. мне действительно трудно в это поверить, но мы также видим эту проблему. возможно, это не совпадение.

2. мы добавили проверки статуса после каждой команды AWS.

3. @tripod Это, безусловно, было бы правильным способом сделать это, но, к сожалению, у меня сейчас нет времени обновлять плагин, о котором я ничего не знаю…

Ответ №2:

в моем случае это решается после того, как я добавил aws:states:opt-out в описание моей лямбды, как описано здесь: https://aws.amazon.com/de/blogs/compute/coming-soon-expansion-of-aws-lambda-states-to-all-functions /

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

1. Я удивлен, что это все еще работает. Я почти уверен, что в какой-то момент отказ от использования больше не будет вариантом.