Rails / 定期的に Amazon S3 のファイルを読み込んで処理するRakeタスク
Amazon S3にファイルが入っていて、
Railsのrakeタスクかなんかで定期的に処理を走らせるみたいな。
そんな事あんまりないかもしれないけど、今回必要だったのでメモ。
例えばこんな状況
- 営業が .csv を Amazon S3 にアップロード
- 定期的にRakeタスクを実行してDBに取り込む
S3はこんな構成になっているとする。
my_bucketの中身を読み込みたい。
- other_bucket
- my_bucket
- data
- record-2015-02-09
- 01.csv
- 02.csv
- record-2015-02-10
- 01.csv
- 02.csv
- record-2015-02-09
- data
他の誰かからS3に安全にアップロードしてもらう方法はこちら。
Developerではない人にはFTPクライアント使ってもらいます。
http://www.workabroad.jp/posts/2131
Gem
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_objects
と get_object
を使うので、
実行できる権限がないと Access Denied
と言われてしまう。
IAMで設定しておきましょう。
CORS
Qiitaでコメントもらいました。CORS必要ないです。
my_bucket の CORS configurationも設定が必要。
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
以上です。
自動化するといろいろ楽ですね。
参考
Class: Aws::S3::Client — AWS SDK for Ruby V2
Class: AWS.Config — AWS SDK for JavaScript