AWS SQS を使う

Jenkins 側(Bash / AWS SQS Cli)

~/.aws/credentials ファイルが設定されていることが前提となる。

#!/bin/bash

export TARGET_HOST='{"hostname":"https://example1.com","username":"user1","password":"pass1"} \
                    {"hostname":"https://example2.com","username":"user2","password":"pass2"}'

export SQS_QUEUE_NAME='eaxmple_queue'

for TARGET_HOST in ${TARGET_HOSTS}; do

  export SQS_QUEUE_URL=$(aws sqs get-queue-url --queue-name ${SQS_QUEUE_NAME} --output text)
  export SQS_MSG_BODY=${TARGET_HOST}
  aws sqs send-message --queue-url ${SQS_QUEUE_URL} --message-body ${SQS_MSG_BODY}

done

上のコードにおいて、Jenkins 側(Bash / AWS SQS Cli)で大事なのは以下の 2行のみ。

export SQS_QUEUE_URL=$(aws sqs get-queue-url --queue-name ${SQS_QUEUE_NAME} --output text)
aws sqs send-message --queue-url ${SQS_QUEUE_URL} --message-body ${SQS_MSG_BODY}

Python 側

キューを処理するロジックがWhile True:で始まっているのはなぜか?これは、receive_messages(MaxNumberOfMessages=10)とオプションを指定し、たとえキューに 2つ以上アイテムがあったとしても 1つしかアイテムが返ってこないときもあるし、ひどいときにはキューにアイテムが溜まっているのになにも返ってこないケースがあるからだ。これは AWS SQS の仕様らしいので、```While True:***で始めて、キューを監視して適宜刈り取っていくしかない。

White True:すると無限ループに陥る可能性が大きくなるが、取得したキューは削除候補のリスト messages_to_deleteに入れて削除する。そして刈り取るキューアイテムがなくなったらWhile True:のループを抜けるようになっている。

# -*- coding: utf-8 -*-

import json
import boto3

sqs = boto3.resource('sqs',
<pre><code>                 aws_access_key_id     = YOUR_AWS_ACCESS_KEY_ID,
                 aws_secret_access_key = YOUR_AWS_SECRET_ACCESS_KEY,
                 region_name           = 'us-west-2')
</code></pre>
sqs_queue_name = YOUR_SQS_QUEUE_NAME
q = sqs.get_queue_by_name(QueueName = sqs_queue_name)

while True:

  messages_to_delete = []
  for message in q.receive_messages(MaxNumberOfMessages = 10, WaitTimeSeconds = 20):

<pre><code>body = json.loads(message.body)
hostname = body['hostname']
username = body['username']
password = body['password']

messages_to_delete.append({
  'Id': message.message_id,
  'ReceiptHandle': message.receipt_handle
})

do_something(hostname, username, password)
</code></pre>
  # if you don't receive any notifications the messages_to_delete list will be empty
  if len(messages_to_delete) == 0:
<pre><code>break
</code></pre>  # delete messages to remove them from SQS queue handle any errors
  else:
<pre><code>q.delete_messages(
  Entries = messages_to_delete
)
</code></pre>