Rails / 定期的に Amazon S3 のファイルを読み込んで処理するRakeタスク

Shunsuke Sawada

Amazon S3にファイルが入っていて、
Railsのrakeタスクかなんかで定期的に処理を走らせるみたいな。
そんな事あんまりないかもしれないけど、今回必要だったのでメモ。

  
s3-rake

例えばこんな状況

S3はこんな構成になっているとする。
my_bucketの中身を読み込みたい。

他の誰かからS3に安全にアップロードしてもらう方法はこちら。
Developerではない人にはFTPクライアント使ってもらいます。
http://www.workabroad.jp/posts/2131

Gem

aws/aws-sdk-ruby

Gemfile

1
gem 'aws-sdk', '~> 2'

S3のデータを読み込む

S3KEY / S3SECRET / S3REGION は環境変数に入れておいてください。
「あるBucketの中のフォルダの中のファイルたち」みたいなのは prefix をつかって指定します。

my_bucket/data/record-2015-02-10 なら
prefix: "data/record-2015-02-10" のように。

/lib/tasks/content.rake

ruby
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
require 'aws-sdk'
def get_records(date)

    bucket = "my_bucket"

    records = []

    Aws.config.update(
      access_key_id: ENV['S3KEY'],
      secret_access_key: ENV['S3SECRET'],
      region: ENV['S3REGION']
    )
    s3 = Aws::S3::Client.new

    s3.list_objects(bucket: bucket, prefix: "data/record-#{date}").contents.each do |obj|
        puts obj.key
        # get_object.body returns StringIO object
        # http://docs.ruby-lang.org/ja/2.0.0/class/StringIO.html
        text = s3.get_object(bucket: bucket, key: obj.key).body.read
        records |= text
    end

    # remove nil
    records.compact!
end

AWSの設定

IAM
list_objectsget_object を使うので、
実行できる権限がないと Access Denied と言われてしまう。
IAMで設定しておきましょう。

  
CORS

Qiitaでコメントもらいました。CORS必要ないです。

my_bucket の CORS configurationも設定が必要。
S3 Management Console

AllowedOrigin が * になってますが適切なものに変えてください。

xml
1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <AllowedMethod>POST</AllowedMethod>
        <AllowedMethod>PUT</AllowedMethod>
        <AllowedHeader>*</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

Rakeタスク

これは普通のrakeタスク。
実行時にオプション渡せるようにもしてる。
こんな感じ。

1
rake content:create["2015-02-09"]

  
何も渡さなければ今日の日付がついたフォルダをS3から探して何かする、と。
HerokuのSchedulerとかで定期的に実行する場合はオプションなしで指定しておけば便利。

/lib/tasks/content.rake

ruby
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
namespace :content do
  desc "Create contents from files in Amazon S3"

  task :create, "date"

  task create: :environment do |task, options|
    if options.date.present?
        date = options.date
    else
        date = Time.current.in_time_zone('Tokyo').strftime('%Y-%m-%d')
    end

    puts date
    records = get_records(date)

    records.each do |record|
      # do something
    end
  end
end

以上です。
自動化するといろいろ楽ですね。

参考

AWS | Tools

Class: Aws::S3::Client — AWS SDK for Ruby V2

Class: AWS.Config — AWS SDK for JavaScript

AWS SDK for Ruby(V2)を利用して、Amazon S3を操作する - Qiita

aws/aws-sdk-ruby

43
Shunsuke Sawada

おすすめの記事

acts-as-taggable-on タグを表示させる順番を決めたい
Railsを4.2にバージョンアップしたら、Vagrantのローカル開発環境にアクセスできなくなった問題
Railsのバリデーションエラー後にレイアウトが崩れるとき