Tutorial Alur Kerja Bagian 3: Menerapkan Aktivitas - Amazon Simple Workflow Service

Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.

Tutorial Alur Kerja Bagian 3: Menerapkan Aktivitas

Sekarang kita akan menerapkan setiap aktivitas dalam alur kerja kita, dimulai dengan kelas dasar yang menyediakan beberapa fitur umum untuk kode aktivitas.

Menentukan Jenis Kegiatan Dasar

Saat mendesain alur kerja, kita mengidentifikasi aktivitas berikut:

  • get_contact_activity

  • subscribe_topic_activity

  • wait_for_confirmation_activity

  • send_result_activity

Kita akan menerapkan tiap-tiap kegiatan ini sekarang. Karena aktivitas kita akan membagikan beberapa fitur, mari kita melakukan sedikit pekerjaan dasar dan membuat beberapa kode umum yang dapat mereka bagikan. Kita akan menyebutnya BasicActivity, dan menetapkannya dalam sebuah file baru bernama basic_activity.rb.

Seperti file sumber lainnya, kita akan menyertakan utils.rb untuk mengakses fungsi init_domain untuk menyiapkan domain sampel.

require_relative 'utils.rb'

Selanjutnya, kita akan menyatakan kelas aktivitas dasar dan beberapa data umum yang akan kita minati untuk setiap aktivitas. Kita akan menyimpan instans AWS::SimpleWorkflow::ActivityType aktivitas, nama, dan hasil dalam atribut kelas.

class BasicActivity attr_accessor :activity_type attr_accessor :name attr_accessor :results

Atribut ini mengakses instans data yang ditentukan dalam metode initialize kelas, yang menggunakan nama aktivitas, dan versi opsional dan peta opsi yang akan digunakan saat mendaftarkan aktivitas dengan Amazon SWF.

def initialize(name, version = 'v1', options = nil) @activity_type = nil @name = name @results = nil # get the domain to use for activity tasks. @domain = init_domain # Check to see if this activity type already exists. @domain.activity_types.each do | a | if (a.name == @name) && (a.version == version) @activity_type = a end end if @activity_type.nil? # If no options were specified, use some reasonable defaults. if options.nil? options = { # All timeouts are in seconds. :default_task_heartbeat_timeout => 900, :default_task_schedule_to_start_timeout => 120, :default_task_schedule_to_close_timeout => 3800, :default_task_start_to_close_timeout => 3600 } end @activity_type = @domain.activity_types.register(@name, version, options) end end

Seperti halnya pendaftaran tipe alur kerja, jika tipe aktivitas sudah terdaftar, kita dapat mengambilnya dengan melihat koleksi activity_types domain. Jika aktivitas tidak dapat ditemukan, aktivitas tersebut akan didaftarkan.

Selain itu, seperti pada tipe alur kerja, Anda dapat mengatur opsi default yang disimpan dengan tipe aktivitas Anda saat Anda mendaftarkannya.

Hal terakhir yang didapatkan aktivitas dasar kita adalah cara konsisten untuk menjalankannya. Kita akan menentukan metode do_activity yang menggunakan tugas aktivitas. Seperti yang ditunjukkan, kita dapat menggunakan tugas aktivitas yang diteruskan untuk menerima data melalui atribut instans input tugas tersebut.

def do_activity(task) @results = task.input # may be nil return true end end

Langkah tersebut mengakhiri kelas BasicActivity. Sekarang kita akan menggunakannya untuk membuat penentuan aktivitas kita menjadi sederhana dan konsisten.

Menentukan GetContactActivity

Aktivitas pertama yang dijalankan selama eksekusi alur kerja adalah get_contact_activity, yang mengambil informasi berlangganan topik Amazon SNS pengguna.

Buat sebuah file baru bernama get_contact_activity.rb, dan harus terdapat yaml, yang akan kita gunakan untuk menyiapkan string untuk meneruskan ke Amazon SWF, dan basic_activity.rb, yang akan kita gunakan sebagai dasar untuk kelas GetContactActivity ini.

require 'yaml' require_relative 'basic_activity.rb' # **GetContactActivity** provides a prompt for the user to enter contact # information. When the user successfully enters contact information, the # activity is complete. class GetContactActivity < BasicActivity

Karena kita memasukkan kode registrasi aktivitas di BasicActivity, metode initialize untuk GetContactActivity cukup sederhana. Kita cukup memanggil konstruktor kelas dasar dengan nama aktivitas, get_contact_activity. Ini semua adalah hal yang diperlukan untuk mendaftarkan aktivitas kita.

# initialize the activity def initialize super('get_contact_activity') end

Kita sekarang akan menentukan metode do_activity, yang meminta email dan/atau nomor telepon pengguna.

def do_activity(task) puts "" puts "Please enter either an email address or SMS message (mobile phone) number to" puts "receive SNS notifications. You can also enter both to use both address types." puts "" puts "If you enter a phone number, it must be able to receive SMS messages, and must" puts "be 11 digits (such as 12065550101 to represent the number 1-206-555-0101)." input_confirmed = false while !input_confirmed puts "" print "Email: " email = $stdin.gets.strip print "Phone: " phone = $stdin.gets.strip puts "" if (email == '') && (phone == '') print "You provided no subscription information. Quit? (y/n)" confirmation = $stdin.gets.strip.downcase if confirmation == 'y' return false end else puts "You entered:" puts " email: #{email}" puts " phone: #{phone}" print "\nIs this correct? (y/n): " confirmation = $stdin.gets.strip.downcase if confirmation == 'y' input_confirmed = true end end end # make sure that @results is a single string. YAML makes this easy. @results = { :email => email, :sms => phone }.to_yaml return true end end

Di akhir do_activity, kita mengambil email dan nomor telepon yang didapatkan dari pengguna, menempatkannya di peta dan kemudian menggunakan to_yaml untuk mengkonversi seluruh peta ke string YAML. Ada alasan penting untuk hal ini: setiap hasil yang Anda teruskan ke Amazon SWF ketika Anda menyelesaikan suatu aktivitas harus berupa data string saja. Kemampuan Ruby untuk dengan mudah mengonversi objek ke string YAML dan kemudian kembali lagi ke objek, untungnya, sesuai untuk tujuan ini.

Itulah akhir dari implementasi get_contact_activity. Data ini akan digunakan selanjutnya di implementasi subscribe_topic_activity.

Menentukan SubscribeTopicActivity

Sekarang kita akan mendalami Amazon SNS dan membuat aktivitas yang menggunakan informasi yang dihasilkan oleh get_contact_activity untuk menjadikan pengguna berlangganan topik Amazon SNS.

Buat sebuah file baru bernama subscribe_topic_activity.rb, tambahkan same requirements (persyaratan yang sama) yang kita gunakan untuk get_contact_activity, declare your class (nyatakan kelas Anda), dan provide its method (sediakan metode initialize).

require 'yaml' require_relative 'basic_activity.rb' # **SubscribeTopicActivity** sends an SMS / email message to the user, asking for # confirmation. When this action has been taken, the activity is complete. class SubscribeTopicActivity < BasicActivity def initialize super('subscribe_topic_activity') end

Sekarang setelah kita menempatkan kode agar aktivitas dapat disiapkan dan terdaftar, kita akan menambahkan beberapa kode untuk membuat topik Amazon SNS. Untuk melakukannya, kita akan menggunakan metode create_topic objek AWS::SNS::Klien.

Tambahkan metode create_topic ke kelas Anda, yang membawa objek klien Amazon SNS yang diteruskan.

def create_topic(sns_client) topic_arn = sns_client.create_topic(:name => 'SWF_Sample_Topic')[:topic_arn] if topic_arn != nil # For an SMS notification, setting `DisplayName` is *required*. Note that # only the *first 10 characters* of the DisplayName will be shown on the # SMS message sent to the user, so choose your DisplayName wisely! sns_client.set_topic_attributes( { :topic_arn => topic_arn, :attribute_name => 'DisplayName', :attribute_value => 'SWFSample' } ) else @results = { :reason => "Couldn't create SNS topic", :detail => "" }.to_yaml return nil end return topic_arn end

Setelah kita memiliki Amazon Resource Name (ARN) topik, kita dapat menggunakannya dengan metode set_topic_attributes klien Amazon SNS untuk mengatur DisplayName topik, yang diperlukan untuk mengirim pesan SMS dengan Amazon SNS.

Terakhir, kita akan menentukan metode do_activity. Kami akan memulai dengan mengumpulkan data apa pun yang diteruskan melalui opsi input ketika aktivitas dijadwalkan. Seperti disebutkan sebelumnya, data ini harus diteruskan sebagai string, yang kita buat menggunakan to_yaml. Saat mengambilnya, kita akan menggunakan YAML.load untuk mengubah data menjadi objek Ruby.

Berikut adalah awal dari do_activity, di mana kita mengambil data input.

def do_activity(task) activity_data = { :topic_arn => nil, :email => { :endpoint => nil, :subscription_arn => nil }, :sms => { :endpoint => nil, :subscription_arn => nil }, } if task.input != nil input = YAML.load(task.input) activity_data[:email][:endpoint] = input[:email] activity_data[:sms][:endpoint] = input[:sms] else @results = { :reason => "Didn't receive any input!", :detail => "" }.to_yaml puts(" #{@results.inspect}") return false end # Create an SNS client. This is used to interact with the service. Set the # region to $SMS_REGION, which is a region that supports SMS notifications # (defined in the file `utils.rb`). sns_client = AWS::SNS::Client.new( :config => AWS.config.with(:region => $SMS_REGION))

Jika kita tidak menerima input apapun, tidak banyak yang harus dilakukan, jadi kita cukup menggagalkan aktivitas.

Dengan asumsi bahwa semuanya baik-baik saja, bagaimanapun, kita akan terus mengisi metode do_activity kita, mendapatkan klien Amazon SNS dengan AWS SDK for Ruby, dan meneruskannya ke metode create_topic untuk membuat topik Amazon SNS.

# Create the topic and get the ARN activity_data[:topic_arn] = create_topic(sns_client) if activity_data[:topic_arn].nil? return false end

Ada beberapa hal yang perlu diperhatikan di sini:

  • Kita menggunakan AWS.config.with untuk mengatur wilayah untuk klien Amazon SNS kita. Karena kita ingin mengirim pesan SMS, kita menggunakan wilayah yang mengaktifkan SMS yang kita nyatakan di utils.rb.

  • Kita menyimpan topik ARN di peta activity_data kita. Ini adalah bagian dari data yang akan diteruskan ke aktivitas selanjutnya dalam alur kerja kita.

Terakhir, aktivitas ini menjadikan pengguna berlangganan topik Amazon SNS, menggunakan titik akhir yang diteruskan (email dan SMS). Kita tidak mengharuskan pengguna untuk masuk ke kedua titik akhir, tapi kita perlu setidaknya satu.

# Subscribe the user to the topic, using either or both endpoints. [:email, :sms].each do | x | ep = activity_data[x][:endpoint] # don't try to subscribe an empty endpoint if (ep != nil && ep != "") response = sns_client.subscribe( { :topic_arn => activity_data[:topic_arn], :protocol => x.to_s, :endpoint => ep } ) activity_data[x][:subscription_arn] = response[:subscription_arn] end end

AWS::SNS::Client.subscribe menggunakan topik ARN, protokol (yang, dengan cerdik, kita samarkan sebagai peta kunci activity_data untuk titik akhir yang sesuai).

Akhirnya, kita memaketkan kembali informasi untuk aktivitas berikutnya dalam format YAML, sehingga kita dapat mengirimkannya kembali ke Amazon SWF.

# if at least one subscription arn is set, consider this a success. if (activity_data[:email][:subscription_arn] != nil) or (activity_data[:sms][:subscription_arn] != nil) @results = activity_data.to_yaml else @results = { :reason => "Couldn't subscribe to SNS topic", :detail => "" }.to_yaml puts(" #{@results.inspect}") return false end return true end end

Hal ini menyelesaikan penerapan subscribe_topic_activity. Selanjutnya, kita akan menentukan wait_for_confirmation_activity.

Menentukan WaitForConfirmationActivity

Setelah pengguna berlangganan topik Amazon SNS, pelanggan masih perlu mengkonfirmasi permintaan berlangganan. Dalam hal ini, kita akan menunggu pengguna untuk mengonfirmasi melalui email atau pesan SMS.

Aktivitas yang menunggu pengguna untuk mengonfirmasi langganan disebut wait_for_confirmation_activity, dan kita akan menentukannya di sini. Untuk memulai, buat file baru bernama wait_for_confirmation_activity.rb dan siapkan file seperti kita menyiapkan aktivitas sebelumnya.

require 'yaml' require_relative 'basic_activity.rb' # **WaitForConfirmationActivity** waits for the user to confirm the SNS # subscription. When this action has been taken, the activity is complete. It # might also time out... class WaitForConfirmationActivity < BasicActivity # Initialize the class def initialize super('wait_for_confirmation_activity') end

Selanjutnya, kita akan mulai menentukan metode do_activity dan mengambil data input apapun ke dalam variabel lokal yang disebut subscription_data.

def do_activity(task) if task.input.nil? @results = { :reason => "Didn't receive any input!", :detail => "" }.to_yaml return false end subscription_data = YAML.load(task.input)

Sekarang setelah kita memiliki topik ARN, kita dapat mengambil topik dengan membuat new instance (instans baru) dari AWS::SNS::Topic dan meneruskan ARN ke instans.

topic = AWS::SNS::Topic.new(subscription_data[:topic_arn]) if topic.nil? @results = { :reason => "Couldn't get SWF topic ARN", :detail => "Topic ARN: #{topic.arn}" }.to_yaml return false end

Sekarang, kita akan memeriksa topik untuk melihat apakah pengguna telah mengonfirmasi langganan menggunakan salah satu titik akhir. Kita hanya akan membutuhkan satu titik akhir yang terkonfirmasi untuk menganggap aktivitas ini berhasil.

Topik Amazon SNS memelihara daftar langganan untuk topik tersebut, dan kita dapat memeriksa apakah pengguna telah mengkonfirmasi langganan tertentu dengan memeriksa untuk melihat apakah ARN langganan diatur menjadi apa pun selain PendingConfirmation.

# loop until we get some indication that a subscription was confirmed. subscription_confirmed = false while(!subscription_confirmed) topic.subscriptions.each do | sub | if subscription_data[sub.protocol.to_sym][:endpoint] == sub.endpoint # this is one of the endpoints we're interested in. Is it subscribed? if sub.arn != 'PendingConfirmation' subscription_data[sub.protocol.to_sym][:subscription_arn] = sub.arn puts "Topic subscription confirmed for (#{sub.protocol}: #{sub.endpoint})" @results = subscription_data.to_yaml return true else puts "Topic subscription still pending for (#{sub.protocol}: #{sub.endpoint})" end end end

Jika kita mendapatkan ARN untuk langganan, kita akan menyimpannya dalam data hasil aktivitas, mengonversinya menjadi YAML, dan mengembalikan true dari do_activity, yang menandakan bahwa aktivitas berhasil diselesaikan.

Karena menunggu langganan dikonfirmasi mungkin membutuhkan beberapa saat, kita akan sesekali memanggil record_heartbeat pada tugas aktivitas. Ini menandakan Amazon SWF bahwa aktivitas masih diproses, dan juga dapat digunakan untuk memberikan pembaruan tentang kemajuan aktivitas (jika Anda melakukan sesuatu, seperti memproses file, yang dapat Anda laporkan kemajuannya).

task.record_heartbeat!( { :details => "#{topic.num_subscriptions_confirmed} confirmed, #{topic.num_subscriptions_pending} pending" }) # sleep a bit. sleep(4.0) end

Langkah ini mengakhiri loop while kita. Jika kita entah bagaimana keluar dari loop tanpa berhasil menyelesaikan proses, kita akan melaporkan kegagalan dan menyelesaikan metode do_activity.

if (subscription_confirmed == false) @results = { :reason => "No subscriptions could be confirmed", :detail => "#{topic.num_subscriptions_confirmed} confirmed, #{topic.num_subscriptions_pending} pending" }.to_yaml return false end end end

Hal ini mengakhiri penerapan wait_for_confirmation_activity. Hanya ada satu aktivitas lagi yang perlu ditentukan: send_result_activity.

Menentukan SendResultActivity

Jika alur kerja telah berkembang sejauh ini, kita telah berhasil menjadikan pengguna berlangganan ke topik Amazon SNS dan pengguna telah mengkonfirmasi langganan.

Aktivitas terakhir kita, send_result_activity, mengiri konfirmasi langganan topik yang berhasil kepada pengguna, menggunakan topik yang menjadi langganan pengguna dan titik akhir yang digunakan pengguna untuk mengonfirmasi langganan.

Buat sebuah file baru bernama send_result_activity.rb dan siapkan seperti kita menyiapkan semua aktivitas sejauh ini.

require 'yaml' require_relative 'basic_activity.rb' # **SendResultActivity** sends the result of the activity to the screen, and, if # the user successfully registered using SNS, to the user using the SNS contact # information collected. class SendResultActivity < BasicActivity def initialize super('send_result_activity') end

Metode do_activity kita dimulai dengan cara yang sama, sekaligus, mendapatkan data input dari alur kerja, mengonversinya dari YAML, dan kemudian menggunakan ARN topik untuk membuat instans AWS::SNS::Topic.

def do_activity(task) if task.input.nil? @results = { :reason => "Didn't receive any input!", :detail => "" } return false end input = YAML.load(task.input) # get the topic, so we publish a message to it. topic = AWS::SNS::Topic.new(input[:topic_arn]) if topic.nil? @results = { :reason => "Couldn't get SWF topic", :detail => "Topic ARN: #{topic.arn}" } return false end

Setelah kita memiliki topik, kita akan mempublikasikan pesan ke topik (dan meneruskannya ke layar, juga).

@results = "Thanks, you've successfully confirmed registration, and your workflow is complete!" # send the message via SNS, and also print it on the screen. topic.publish(@results) puts(@results) return true end end

Penerbitan ke topik Amazon SNS mengirimkan pesan yang Anda suplai ke semua titik akhir langganan dan yang terkonfirmasi yang ada untuk topik tersebut. Jadi, jika pengguna mengonfirmasi dengandua cara yaitu email dan nomor SMS, pelanggan akan menerima dua pesan konfirmasi, satu di setiap titik akhir.

Langkah selanjutnya

Langkah ini menyelesaikan penerapan send_result_activity. Sekarang, Anda akan mengikat semua aktivitas ini bersama-sama dalam aplikasi aktivitas yang menangani tugas-tugas aktivitas dan dapat meluncurkan aktivitas sebagai respons, di Tutorial Alur Kerja Langganan Bagian 4: Menerapkan Poller Tugas Aktivitas.