Closed tommyalvarez closed 1 year ago
Thanks for reporting this issue. Can you run with the environment variable APPMAP_LOG_HOOK as described here - https://appmap.io/docs/reference/appmap-ruby.html#advanced-runtime-options
and share the resulting log file? If you don’t want to attach it here, you can send us a DM through the AppMap Slack. This way we can see which method is causing the error, and we will be able to tell you how to disable it and get your app running again while we fix the problem.
Hi @kgilpin.
Attaching the logs appmap_hook.log
Thanks, here's what I see so far. AppMap is recording a method call to this function:
#15 facebook_conversions_api_add_to_cart at app/controllers/concerns/facebook_conversions_api/tracking_helpers.rb:10
As it records that function, it's writing out the data for the self and arguments. That logic includes this snippet:
def detect_size(value)
# Don't risk calling #size on things like data-access objects, which can and will issue queries for this information.
if value.is_a?(Array) || value.is_a?(Hash)
value.size
end
end
value
in this case appears to be a Delayed::DelayedProxy
(from delayed_job
, because that's what is next up the call stack).
The DelayedProxy has indicated that it is an Array or Hash - I don't see how this is possible, but it seems to be happening.
AppMap then tries to call the size
method on the DelayedProxy. The DelayedProxy creates a PerformableObject, which raises #<NoMethodError: undefined method
size' for FacebookConversionsApi>`
FacebookConversionsApi
may be self
or it may be a parameter of the method indicated earlier, app/controllers/concerns/facebook_conversions_api/tracking_helpers.rb:10
.
Somehow, FacebookConversionsApi
is return true from value.is_a?(Array) || value.is_a?(Hash)
, but it does not implement size
. I don't honestly know how this is possible - it may be evident from looking at the code.
You can disable recording of facebook_conversions_api_add_to_cart
using appmap.yml.
Add the fully qualified class name and method name to the exclude
section (as described here:
name: my_project
language: ruby
appmap_dir: tmp/appmap
packages:
- path: app
exclude:
- FacebookConversionsApi::TrackingHelpers#facebook_conversions_api_add_to_cart
To fix this in appmap-ruby, I'll add a guard clause to verify that :size
is really defined on value
.
:tada: This issue has been resolved in version 0.102.1 :tada:
The release is available on:
v0.102.1
Your semantic-release bot :package::rocket:
@kgilpin unfortunately, even with the fix the issue is still happening in the same place. Even the workaround won't have any effect.
I believe that the issue might be that value
is like a method or proc that gets called when referenced, so it returns "something", and for the purpose of the if
that evaluates if it's a hash
, array
or even respond_to :size
, it returns a non-nil value so it evaluates as a truthy.
The funny thing is that each time value
gets referenced at this point, even with a method, it enqueues a new job for me. For instance I was able to debug the point where the bug happens and see for yourself:
[12, 21] in /Users/tommy/.rvm/gems/ruby-3.0.5/gems/appmap-0.102.1/lib/appmap/value_inspector.rb
12: value.size
13: end
14: rescue NoMethodError => e
15: byebug
16: end
=> 17: end
18:
19: def detect_schema(
test = value.is_a?(Array)
2023-07-25 17:50:14.812 [DEBUG] TRANSACTION (12.3ms) BEGIN (pid:22960)
2023-07-25 17:50:14.816 [DEBUG] ↳ .../app/controllers/concerns/facebook_conversions_api/tracking_helpers.rb:9:in `facebook_conversions_api_add_to_cart' (pid:22960)
2023-07-25 17:50:14.818 [DEBUG] Delayed::Backend::ActiveRecord::Job Create (0.9ms) INSERT INTO "delayed_jobs" ("handler", "run_at", "queue", "created_at", "updated_at") VALUES ('--- !ruby/object:Delayed::PerformableMethod
object: !ruby/module ''FacebookConversionsApi''
method_name: :is_a?
args:
- !ruby/class ''Array''
', '2023-07-25 20:50:14.798890', 'default', '2023-07-25 20:50:14.798954', '2023-07-25 20:50:14.798954') RETURNING "id" (pid:22960)
2023-07-25 17:50:14.818 [DEBUG] ↳ .../app/controllers/concerns/facebook_conversions_api/tracking_helpers.rb:9:in `facebook_conversions_api_add_to_cart' (pid:22960)
2023-07-25 17:50:14.819 [DEBUG] Query Trace:
app/controllers/concerns/facebook_conversions_api/tracking_helpers.rb:9:in `facebook_conversions_api_add_to_cart'
app/controllers/concerns/checkout_helpers.rb:62:in `handle_line_item_addition'
app/controllers/concerns/checkout_helpers.rb:53:in `order_line_items_updated_callbacks'
app/controllers/api/line_items_controller.rb:94:in `handle_create_or_update'
app/controllers/api/line_items_controller.rb:32:in `create' (pid:22960)
2023-07-25 17:50:14.819 [DEBUG] ↳ .../app/controllers/concerns/facebook_conversions_api/tracking_helpers.rb:9:in `facebook_conversions_api_add_to_cart' (pid:22960)
2023-07-25 17:50:14.820 [DEBUG] TRANSACTION (0.5ms) COMMIT (pid:22960)
2023-07-25 17:50:14.820 [DEBUG] ↳ .../app/controllers/concerns/facebook_conversions_api/tracking_helpers.rb:9:in `facebook_conversions_api_add_to_cart' (pid:22960)
#<Delayed::Backend::ActiveRecord::Job id: 2566514, priority: 0, attempts: 0, handler: "--- !ruby/object:Delayed::PerformableMethod\nobject...", last_error: nil, run_at: "2023-07-25 16:50:14.798890000 -0400", locked_at: nil, failed_at: nil, locked_by: nil, queue: "default", created_at: "2023-07-25 16:50:14.798954000 -0400", updated_at: "2023-07-25 16:50:14.798954000 -0400">
(byebug) test
#<Delayed::Backend::ActiveRecord::Job id: 2566514, priority: 0, attempts: 0, handler: "--- !ruby/object:Delayed::PerformableMethod\nobject...", last_error: nil, run_at: "2023-07-25 16:50:14.798890000 -0400", locked_at: nil, failed_at: nil, locked_by: nil, queue: "default", created_at: "2023-07-25 16:50:14.798954000 -0400", updated_at: "2023-07-25 16:50:14.798954000 -0400">
I think the issue should be reopened.
What's interesting / weird is that appmap-ruby isn't calling a method on the object, it's using is_a?
https://github.com/getappmap/appmap-ruby/blob/master/lib/appmap/value_inspector.rb#L10
An object that overrides is_a?
to always return true is definitely asking for trouble. And I guess if it's overriding respond_to?
to also always return true, then it's even more so.
Because the object is wrapped with a proxy, calling any method on it causes it to be enqueued:
https://github.com/collectiveidea/delayed_job/blob/master/lib/delayed/message_sending.rb#L11
That's why you are seeing that behavior.
So the solution will definitely be to find out which method is triggering this behavior and add it to the exclude:
list in the config file. It looks to me like the thing to exclude is #15 facebook_conversions_api_add_to_cart at app/controllers/concerns/facebook_conversions_api/tracking_helpers.rb:10
. The hook log file should show this method being skipped over during instrumentation. If it's not, maybe Spring needs to be disabled or restarted?
I'm using the AppMap ruby agent to build sequence diagrams. I'm using the record feature of the gem.
It would seem that some hooks added by the agent are causing issues and my app to crash. Some info of the app:
Ruby version: 3.0.5 Rails: 6.1.7.1 appmap (0.102.0)
Stacktrace:
The key part seems to be here:
Where app map tries to inspect a value. The value inspected remains unknown to me, as it's a little bit tricky to debug the code at that point, but it starts from a Delayed job method call to
#delay
with a hash argument.Unfortunately, this is impeding me to fully use appmap as it crashes my application on a very important flow.