amazon-archives / aws-flow-ruby

ARCHIVED
137 stars 58 forks source link

undefined method `_options' for nil:NilClass; [aws/decider/utilities.rb:183] #76

Closed kalpitad closed 9 years ago

kalpitad commented 9 years ago

For background, I have a simple workflow with one activity running in an AWS Flow for Ruby layer on Opsworks. I have a separate REST API running in a Rails App Server layer on Opsworks that I would like to kick off the workflow.

The code in the REST API that kicks off the workflow:

require 'aws/decider'

domain = AWS::SimpleWorkflow.new.domains['my_domain']
workflow_client = AWS::Flow::workflow_client(domain.client, domain) {{from_class: MyWorkflowClass}}
workflow_client.start_execution(input_1: @input1, input_2: @input2)

Error trace:

undefined method `_options' for nil:NilClass; ["/Users/MyName/.rvm/gems/ruby-2.0.0-p247/gems/aws-flow-2.2.1/lib/aws/decider/utilities.rb:183:in `interpret_block_for_options'", "/Users/MyName/.rvm/gems/ruby-2.0.0-p247/gems/aws-flow-2.2.1/lib/aws/decider/implementation.rb:73:in `workflow_client'"

My assumption is that my workflow and REST API code bases could be separate and that the only common component would be the aws-flow Ruby gem and require 'aws/decider'. However, I'm finding that my REST API also needs to have require 'PATH_TO_MY_WORKFLOW_CLASS'. Is this true? It's the only thing that I can do to get the error to go away. The reason why I am not satisfied with this is because requiring the workflow class in the starter code does not make any sense to me. It binds the two apps way too tightly. Is this indeed the requirement or is there a bug here?

Thank you!

pmohan6 commented 9 years ago

Thanks a lot for the question @kalpitad.

There are two ways of starting the workflow in code - 1) Using the aws sdk directly. In this case, your code doesn't need to know anything about the workflow class. You just need the domain, workflow type (name and version) and the workflow id It will look something like -

require 'aws-sdk-v1'
swf = AWS::SimpleWorkflow.new.client
swf.start_workflow_execution(
  domain: "HelloWorld",
  workflow_type: {
    name: "HelloWorldWorkflow",
    version: "1.0"
  },
  workflow_id: "foo",
  input: ....,
  ....other options (optional)...
)

As you can see above, this doesn't require the workflow class at all.

2) Using the aws-flow gem (which is what you are doing above). There are two ways of using the workflow client provided by the aws-flow gem to start an execution. You can either use the client as a generic client and not tie it to any workflow class or you can use the :from_class option to fetch options from a particular workflow class. To use the from_class option, you need to have the class in the ObjectSpace (hence you need to require the workflow file).

require 'aws/decider'
domain = AWS::SimpleWorkflow.new.domains['my_domain']
workflow_client = AWS::Flow::workflow_client(domain.client, domain) {{from_class: "MyWorkflowClass"}}
workflow_client.start_execution(input_1: @input1, input_2: @input2)
require 'aws/decider'
domain = AWS::SimpleWorkflow.new.domains['my_domain']
workflow_client = AWS::Flow::workflow_client(domain.client, domain) {{
  prefix_name: "YourClassName",
  execution_method: "workflow_method_name",
  version: "1.0",
  ...other options...
}}
workflow_client.start_execution(input_1: @input1, input_2: @input2)

You don't have to use :from_class option at all. It's only there for convenience.

kalpitad commented 9 years ago

@pmohan6, thank you so much! The prefix_name and execution_method options worked perfectly for me.

But, to be honest, when I go back and look at the API documentation, I can't even see that these options are a possibility and all the samples that I look at (e.g. Hello World Tutorial) use the from_class option, so it's not clear that there is another way. Updating the documentation and samples to show all the options that you mentioned above would be super helpful to other developers like me. http://docs.aws.amazon.com/amazonswf/latest/awsrbflowapi/AWS/Flow/WorkflowClient.html#initialize-instance_method

Thanks again! I really appreciate you taking the time to answer my question. :)

kalpitad commented 9 years ago

Oh, one more thought... I had thought about the option of using the aws sdk directly. The downside is that when you start the execution, it seems like you can only pass in a single string as input. I could have hacked this for my needs if it had been my only choice, but using a hash definitely keeps my code cleaner. This also seems to be an issue when kicking off a workflow manually from the SWF Management Console -- only a single string can be passed in as input. Thanks again!

EronHennessey commented 9 years ago

FYI, the documentation in the Developer Guide regarding activity/workflow options has been updated:

http://docs.aws.amazon.com/amazonswf/latest/awsrbflowguide/programming-options.html

While from_class is still there, many more ways of setting options are discussed now... ;)

kalpitad commented 9 years ago

@EronHennessey, sweet! :)

One suggestion is to also add the prefix_name option in the 'Workflow Runtime Options' section, because that coupled with execution_method and version help a developer initialize the exact workflow client that they will later call start_execution on.

pmohan6 commented 9 years ago

Really appreciate the feedback @kalpitad.

You are correct - the SDK and the console will only take strings as input. This can be a free form string but if your workflow is written using ruby flow, this string should be a serialized form of your input so that the WorkflowWorker can deserialize the input when it picks up the task and convert it into ruby objects (in this case a hash).

When you use the ruby flow WorkflowClient, the client will automatically serialize your input hash (or any other input) into a string before sending it to SWF. aws-flow by default uses a YAML based data converter to do this (It can be overridden).

If you just want to see what your input hash will look like as a string, you can do the following -

AWS::Flow::FlowConstants.default_data_converter.dump(input_hash) 

You can then use this serialized input to start a workflow using the SDK or the console.

The recommended way to start a workflow execution is to use aws-flow WorkflowClient instead of using the SDK directly as mentioned in the previous post.

kalpitad commented 9 years ago

@pmohan6 Got it, thank you very much for info!