rubyonjets/jets

Preheat Error after deploy - undefined local variable or method `cfn' for #<Jets::Preheat:>

Closed this issue ยท 9 comments

Checklist

  • Upgrade Jets: Are you using the latest version of Jets? This allows Jets to fix issues fast. There's a jets upgrade command that makes this a simple task. There's also an Upgrading Guide: http://rubyonjets.com/docs/upgrading/
  • Reproducibility: Are you reporting a bug others will be able to reproduce and not asking a question. If you're unsure or want to ask a question, do so on https://community.boltops.com
  • Code sample: Have you put together a code sample to reproduce the issue and make it available? Code samples help speed up fixes dramatically. If it's an easily reproducible issue, then code samples are not needed. If you're unsure, please include a code sample.

My Environment

Software Version
Operating System public.ecr.aws/sam/build-ruby3.2:latest-arm64
Jets 4.0.1
Ruby 3.2

Expected Behavior

After upgrade to 4.0.1 from v3, I ran the jets deploy command and expected the deploy to finish successfully.

Current Behavior

After UPDATE_COMPLETE, An error occurred when starting Preheat Job.

Step-by-step reproduction instructions

10:57:37AM DELETE_IN_PROGRESS AWS::Lambda::LayerVersion GemLayer 
10:57:37AM UPDATE_COMPLETE AWS::CloudFormation::Stack ApiGateway 
10:57:38AM DELETE_COMPLETE AWS::Lambda::LayerVersion GemLayer 
10:57:38AM UPDATE_COMPLETE AWS::CloudFormation::Stack *********** 
Stack success status: UPDATE_COMPLETE
Time took: 1m 23s
Prewarming application.
/var/lang/lib/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/preheat.rb:94:in `all_functions': undefined local variable or method `cfn' for #<Jets::Preheat:0x0000ffffa2bc0cf8 @options={:mute=>true, :mute_output=>true, :invocation_type=>"Event", :lambda_proxy=>false}> (NameError)

      parent_stack = cfn.describe_stack_resources(stack_name: Jets::Names.parent_stack_name)
                     ^^^
        from /var/lang/lib/ruby/gems/3.2.0/gems/memoist-0.16.2/lib/memoist.rb:169:in `all_functions'
        from /var/lang/lib/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/preheat.rb:32:in `warm_all'
        from /var/lang/lib/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/preheat.rb:15:in `warm_all'
        from /var/lang/lib/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/internal/app/jobs/jets/preheat_job.rb:51:in `warm'
        from /var/lang/lib/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/job/base.rb:31:in `perform_now'
        from /var/lang/lib/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/internal/app/jobs/jets/preheat_job.rb:59:in `prewarm!'
        from /var/lang/lib/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/cfn/ship.rb:108:in `prewarm'
        from /var/lang/lib/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/cfn/ship.rb:46:in `run'
        from /var/lang/lib/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/commands/deploy.rb:75:in `ship'
        from /var/lang/lib/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/commands/deploy.rb:36:in `run'
        from /var/lang/lib/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/commands/main.rb:27:in `deploy'
        from /var/lang/lib/ruby/gems/3.2.0/gems/thor-1.2.2/lib/thor/command.rb:27:in `run'
        from /var/lang/lib/ruby/gems/3.2.0/gems/thor-1.2.2/lib/thor/invocation.rb:127:in `invoke_command'
        from /var/lang/lib/ruby/gems/3.2.0/gems/thor-1.2.2/lib/thor.rb:392:in `dispatch'
        from /var/lang/lib/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/commands/base.rb:38:in `dispatch'
        from /var/lang/lib/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/commands/base.rb:27:in `perform'
        from /var/lang/lib/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/cli.rb:28:in `start'
        from /var/lang/lib/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/cli.rb:5:in `start'
        from /var/lang/lib/ruby/gems/3.2.0/gems/jets-4.0.1/exe/jets:14:in `<top (required)>'
        from /var/lang/bin/jets:25:in `load'
        from /var/lang/bin/jets:25:in `<main>'

Code Sample

nothing.

Solution Suggestion

nothing.

It looks like the fix for this is to add include Jets::AwsServices to the Preheat class in preheat.rb

Snippet

module Jets
  class Preheat
    extend Memoist
    include Jets::AwsServices              # This fixes the reference to cfn
...

@NacchaF Thanks for the report
@dmorehouse Thanks for debugging and figuring out the issue

Feel free to do the honors of sending a PR. Or anyone else for that matter. Of course, no sweat either way ๐Ÿ‘

I'm verifying my fix works and if it does I'll send over a PR.

Turns out this is more complicated than it originally looked. After adding include Jets::AwsServices to the Preheat class. I now get the following error.

er.rb:41:in `delegate_guesser'
#<Thread:0x00007ff35482f0b0 /opt/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/preheat.rb:36 run> terminated with exception (report_on_exception is true):
/opt/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/commands/call/guesser.rb:30:in `class_name'
/opt/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/commands/call.rb:87:in `ensure_guesses_found!'
/opt/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/commands/call/guesser.rb:41:in `delegate_guesser': undefined method `=~' for #<struct Aws::CloudFormation::Types::StackResource stack_name="techbot-dev-JetsPublicController-62MKSS3H6CEM", stack_id="arn:aws:cloudformation:us-east-2:962773200528:stack/techbot-dev-JetsPublicController-62MKSS3H6CEM/2a40dc30-724f-11ed-89e4-0aef3ea0d208", logical_resource_id="ShowPermission", physical_resource_id="techbot-dev-JetsPublicController-62MKSS3H6CEM-ShowPermission-1NUI24P7P81SG", resource_type="AWS::Lambda::Permission", timestamp=2023-07-28 21:18:42.568 UTC, resource_status="UPDATE_COMPLETE", resource_status_reason=nil, description=nil, drift_information=#<struct Aws::CloudFormation::Types::StackResourceDriftInformation stack_resource_drift_status="NOT_CHECKED", last_check_timestamp=nil>, module_info=nil> (NoMethodError)
from /opt/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/commands/call/guesser.rb:30:in `class_name'
from /opt/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/commands/call.rb:87:in `ensure_guesses_found!'
from /opt/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/commands/call.rb:21:in `function_name'
from /opt/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/commands/call.rb:51:in `remote_run'
from /opt/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/commands/call.rb:29:in `run'
from /opt/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/preheat.rb:27:in `warm'
from /opt/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/preheat.rb:37:in `block (2 levels) in warm_all'
/opt/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/commands/call.rb:21:in `function_name'
/opt/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/commands/call.rb:51:in `remote_run'
/opt/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/commands/call.rb:29:in `run'
/opt/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/preheat.rb:27:in `warm'
/opt/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/preheat.rb:37:in `block (2 levels) in warm_all'
Critical exception from handler
{
  "errorMessage": "undefined method `=~' for #<struct Aws::CloudFormation::Types::StackResource stack_name=\"techbot-dev-JetsPublicController-62MKSS3H6CEM\", stack_id=\"arn:aws:cloudformation:us-east-2:962773200528:stack/techbot-dev-JetsPublicController-62MKSS3H6CEM/2a40dc30-724f-11ed-89e4-0aef3ea0d208\", logical_resource_id=\"CatchallShowAnyApiMethod\", physical_resource_id=\"techb-Catch-SN2HLNOGS9NU\", resource_type=\"AWS::ApiGateway::Method\", timestamp=2023-07-28 21:18:42.925 UTC, resource_status=\"UPDATE_COMPLETE\", resource_status_reason=nil, description=nil, drift_information=#<struct Aws::CloudFormation::Types::StackResourceDriftInformation stack_resource_drift_status=\"NOT_CHECKED\", last_check_timestamp=nil>, module_info=nil>",
  "errorType": "Function<NoMethodError>",
  "stackTrace": [
    "/opt/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/commands/call/guesser.rb:41:in `delegate_guesser'",
    "/opt/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/commands/call/guesser.rb:30:in `class_name'",
    "/opt/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/commands/call.rb:87:in `ensure_guesses_found!'",
    "/opt/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/commands/call.rb:21:in `function_name'",
    "/opt/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/commands/call.rb:51:in `remote_run'",
    "/opt/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/commands/call.rb:29:in `run'",
    "/opt/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/preheat.rb:27:in `warm'",
    "/opt/ruby/gems/3.2.0/gems/jets-4.0.1/lib/jets/preheat.rb:37:in `block (2 levels) in warm_all'"

@dmorehouse Oh I see. Ran into this in a WIP Jets v5 and fixed in it there. Unsure how long jets v5 is going to take. Maybe a few weeks out. So let's try backporting this fix.

I took the diff of master..v5 and adjusted it. Here's the relevant diff that should help. Haven't tested the specific diff below yet.

@@ -17,11 +17,13 @@ class Jets::Commands::Call
   end
 
   def function_name
-    if @guess
+    if @provided_function_name.starts_with?(Jets.config.project_namespace)
+      @provided_function_name # fully qualified function name
+    elsif @guess
       ensure_guesses_found! # possibly exits here
       guesser.function_name # guesser adds namespace already
     else

That should result in the function name lookup to be correct to the Jets#call method, since the fully qualified name is already being passed in.

Maybe give that a try. Again, no sweat either way ๐Ÿ‘ Thanks for your time.

@tongueroo I appreciate you taking the time to share the diff with me. Unfortunately, that change is a beyond my current comfort level with this project. I'll leave this to you or another first timer in this project. Again thanks for all your time.

All good! Thanks!

@tongueroo I took another try using your suggestion and it still failed. Debugging it looks like the problem moves to preheat.rb all_functions which is returning a struct not a function name. I get this error
undefined method 'starts_with?' for #<struct Aws::CloudFormation::Types::StackResource stack_name="techbot-dev-JetsPublicController-62MKSS3H6CEM", ...

You can see my implementation here - https://github.com/dmorehouse/jets/tree/fix-prewarming

Here's the full stacktrace from the Lambda console

gems/3.2.0/bundler/gems/jets-507332257644/lib/jets/commands/call.rb:31:in `run'
from /opt/ruby/gems/3.2.0/bundler/gems/jets-507332257644/lib/jets/preheat.rb:28:in `warm'
from /opt/ruby/gems/3.2.0/bundler/gems/jets-507332257644/lib/jets/preheat.rb:38:in `block (2 levels) in warm_all'
Calling warm for function: '#<struct Aws::CloudFormation::Types::StackResource stack_name="techbot-dev-JetsPublicController-62MKSS3H6CEM", stack_id="arn:aws:cloudformation:us-east-2:962773200528:stack/techbot-dev-JetsPublicController-62MKSS3H6CEM/2a40dc30-724f-11ed-89e4-0aef3ea0d208", logical_resource_id="ShowGetApiMethod", physical_resource_id="techb-ShowG-RFB23I5KXTZP", resource_type="AWS::ApiGateway::Method", timestamp=2023-07-28 21:18:42.986 UTC, resource_status="UPDATE_COMPLETE", resource_status_reason=nil, description=nil, drift_information=#<struct Aws::CloudFormation::Types::StackResourceDriftInformation stack_resource_drift_status="NOT_CHECKED", last_check_timestamp=nil>, module_info=nil>'
#<Thread:0x00007fd747286d08 /opt/ruby/gems/3.2.0/bundler/gems/jets-507332257644/lib/jets/preheat.rb:37 run> terminated with exception (report_on_exception is true):
/opt/ruby/gems/3.2.0/bundler/gems/jets-507332257644/lib/jets/commands/call.rb:20:in `function_name': undefined method `starts_with?' for #<struct Aws::CloudFormation::Types::StackResource stack_name="techbot-dev-JetsPublicController-62MKSS3H6CEM", stack_id="arn:aws:cloudformation:us-east-2:962773200528:stack/techbot-dev-JetsPublicController-62MKSS3H6CEM/2a40dc30-724f-11ed-89e4-0aef3ea0d208", logical_resource_id="ShowGetApiMethod", physical_resource_id="techb-ShowG-RFB23I5KXTZP", resource_type="AWS::ApiGateway::Method", timestamp=2023-07-28 21:18:42.986 UTC, resource_status="UPDATE_COMPLETE", resource_status_reason=nil, description=nil, drift_information=#<struct Aws::CloudFormation::Types::StackResourceDriftInformation stack_resource_drift_status="NOT_CHECKED", last_check_timestamp=nil>, module_info=nil> (NoMethodError)
if @provided_function_name.starts_with?(Jets.config.project_namespace)
^^^^^^^^^^^^^
from /opt/ruby/gems/3.2.0/bundler/gems/jets-507332257644/lib/jets/commands/call.rb:53:in `remote_run'
from /opt/ruby/gems/3.2.0/bundler/gems/jets-507332257644/lib/jets/commands/call.rb:31:in `run'
from /opt/ruby/gems/3.2.0/bundler/gems/jets-507332257644/lib/jets/preheat.rb:28:in `warm'
from /opt/ruby/gems/3.2.0/bundler/gems/jets-507332257644/lib/jets/preheat.rb:38:in `block (2 levels) in warm_all'
Critical exception from handler
{
  "errorMessage": "undefined method `starts_with?' for #<struct Aws::CloudFormation::Types::StackResource stack_name=\"techbot-dev-JetsPublicController-62MKSS3H6CEM\", stack_id=\"arn:aws:cloudformation:us-east-2:962773200528:stack/techbot-dev-JetsPublicController-62MKSS3H6CEM/2a40dc30-724f-11ed-89e4-0aef3ea0d208\", logical_resource_id=\"CatchallShowAnyApiMethod\", physical_resource_id=\"techb-Catch-SN2HLNOGS9NU\", resource_type=\"AWS::ApiGateway::Method\", timestamp=2023-07-28 21:18:42.925 UTC, resource_status=\"UPDATE_COMPLETE\", resource_status_reason=nil, description=nil, drift_information=#<struct Aws::CloudFormation::Types::StackResourceDriftInformation stack_resource_drift_status=\"NOT_CHECKED\", last_check_timestamp=nil>, module_info=nil>",
  "errorType": "Function<NoMethodError>",
  "stackTrace": [
    "/opt/ruby/gems/3.2.0/bundler/gems/jets-507332257644/lib/jets/commands/call.rb:20:in `function_name'",
    "/opt/ruby/gems/3.2.0/bundler/gems/jets-507332257644/lib/jets/commands/call.rb:53:in `remote_run'",
    "/opt/ruby/gems/3.2.0/bundler/gems/jets-507332257644/lib/jets/commands/call.rb:31:in `run'",
    "/opt/ruby/gems/3.2.0/bundler/gems/jets-507332257644/lib/jets/preheat.rb:28:in `warm'",
    "/opt/ruby/gems/3.2.0/bundler/gems/jets-507332257644/lib/jets/preheat.rb:38:in `block (2 levels) in warm_all'"
  ]
}

@dmorehouse Thanks for the debugging and commits. Merged your branch into this #660 PR and fixed function_names call that was causing the error you posted above.