amazon-archives/aws-sdk-core-ruby

Client responses are not Rails cache-able, because they are not marshal-able

Closed this issue · 5 comments

I am writing a rails web console for my team, and I want to provide them with a page which displays all of our deployed Cloudformation stacks. The CF API is not very robust... To load the CF page, it takes over a minute, because I have to hit multiple regions.

I wanted to cache the results of #describe_stacks, using Rails.cache and the redis-rails gem. I can not, because Struct objects are not marshal-able. It seems like to the easiest solution to this problem it to replace the Structs with OpenStructs, or another object which is also marshal-able.

Any thoughts on how likely it is we can change this?

Call #to_h on the response and you will receive a deep copy of the structs as vanilla hashes.

Calling #to_h seems like a kludge, a work around while we try to figure out if anything else makes sense.

Converting to a hash seems like it would lead to a decent amount of cognitive dissonance. In my console project, my structs will be hashes... But in any other project I'm working on, I'll have Struct objects. The call chains will look different, and using hashes, the code will be uglier...

Given the choice between converting all of my results to hashes and having a slow page, I have to say I'm likely to make people wait. Any other coder who looks at the console code will scratch their head.

Is this as good as it'll get, for marshalling Aws objects?

I'm opposed to using OpenStruct because it fails to provide any safety when accessing attributes. Open struct will gladly set or get any property, making it very trivial to create or mask bugs.

What about using a converter like the following to translate structs into open structs?

def struct_2_ostruct(obj)
  case obj
  when Struct 
    obj.each_pair.with_object(OpenStruct.new) do |(key,value),struct|
      struct[key] = struct_2_ostruct(value)
    end
  when Hash 
    obj.each.with_object({}) do |(key,value),hash|
      hash[key] = struct_2_ostruct(value)
    end
  when Array 
    obj.map {|value| struct_2_ostruct(value) }
  else
    obj
  end
end

If you are comfortable with the caveats of open struct, this preserves the method access modes and should be safe for marshalling.

I can understand the opposition to OpenStruct, that would be quite a hairy nightmare. I'll take a look at this conversion option, thanks for your input!

No problem. I'm going to mark this mark this ticket as closed. Please feel free to also continue the discussion in our gitter channel: https://gitter.im/aws/aws-sdk-core-ruby