New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ReactiveCocoa does not work well with NewRelic agent (or vice versa) #1561
Comments
Without seeing the code, it's hard to know where the issue specifically lies. However, an easy workaround would be to avoid the use of |
I think that not using rac_signalForSelector will affect our architecture in a negative way. I would rather fix this issue. As NewRelic is closed-source I am not able to fix it myself, but I already started work with NewRelic team and provided them necessary prerequisites to reproduce and fix. Working on a simplified application to reproduce an issue as well. |
I was able to reproduce issue and delivered example application to Newrelic team. There is no answer yet why it is happening, and it is hard to investigate on what side things goes wrong, as loop happening after RAC swizzling in Newrelic code. The code to reproduce is as simple as:
Newrelic team aware about this issue, so if there will be some issues related to RAC I think they will follow up here. |
It looks like RAC and Newrelic swizzling a same method and somehow causing an infinite loop. I encountered a similar problem while using RAC and BlocksKit together before and it's hard to solve. People claim method swizzling is evil for a reason. |
I'm not sure if this is helpful or not but I think Aspects had a similar issue with New Relic: It looks like @steipete's fix will be to re-implement how Aspects performs method swizzling based on this New Relic blog post: http://blog.newrelic.com/2014/04/16/right-way-to-swizzle/ |
Yes, they proposed a different way of swizzling which has it's own drawbacks... haven't actually gotten into updating Aspects for that, especially also because NewRelic's framework is closed source, obfuscated and also protected against reverse engineering - so debugging with it is next to impossible. Their support also ignored my issues for the longest time. |
According to NewRelic team swizzling in RAC done incorrectly, that causing NewRelic to fail. I requested them to post here more details about NR internal swizzling and how they see RAC swizzling to be fixed. Without that information I do not believe this task will move forward. |
Actually link provided in support ticket by NewRelic are the same as @powerje posted. |
Application that reproduce an issue available here— https://github.com/BuddyHOPP/NewrelicInfiniteLoopIssue |
The issue lies in how New Relic dynamically swizzles system methods. It depends on the method's _cmd parameter to match the system's default signature. The best way to solve this problem is to ensure the cmd value of swizzled methods isn't populated with "@selector(rac_alias<method_name>)" and instead populated with "@selector(<method_name>)". Not sure if this is feasible with the way reactive cocoa does swizzling. |
There's a really long-winded explanation here, but the TLDR is that it's really not possible for us to affect @nikita-leonov As I mentioned above, it's probably in your best interest to avoid it. But you only need to avoid it for classes affected by NewRelic. /cc @kastiglione @Coneko @joshvera @keithduncan who know a lot about the swizzling too |
@jspahrsummers unfortunately it is almost like say "do not use signalForSelector at all" It will also cause us to refactor a lot of things that are already in place. It will be interesting to know actually details why RAC is incompatible with approach that NewRelic suggested, as it looks pretty legit. |
@nikita-leonov Does NewRelic document what they swizzle? |
@kastiglione it would be nice question to ask, I will do so. In my understanding they swizzle almost everything, as they measure time of execution of calls, but I actually do not know how deep they are going down to. I will post here more information, as it may be helpful for temporary workaround. |
Here's a table of the things we swizzle. We will also swizzle anything that subclasses these methods. https://docs.newrelic.com/docs/mobile-monitoring/mobile-sdk-api/new-relic-mobile-sdk-api/working-ios-sdk-api#instrumenting |
@buchananbryce Thanks! |
@buchananbryce Why not just add a check that strips "rac_alias_" prefixes? Not elegant, but I'm sure it would make happy customers. Or if that's too specific, maybe provide an API for apps to map swizzled selectors. You say yourself "The issue lies in how New Relic dynamically swizzles system methods.". I'm making lots of assumptions, but that's because I'm not much clear of "why". |
It's not really feasible to add a string compare for every possible framework that could be swizzling, and again, it's not really feasible to expect any person to know which prefixes to search for... I feel like 'there be dragons' going down this rabbit hole for a solution. The 'why' is New Relic relies on the _cmd parameter to match it's default value, to allow us to instrument a variable number of methods without any sort of user intervention to make it happen, and ideally, when swizzling, the _cmd value should always match the name of the method that's being executed. I see that you are swizzling the forwardInvocation method; would it be possible for you to manipulate the _cmd parameter in the invocation's parameter list before forwarding it on at that point? |
@buchananbryce Hmm, that's a good question that hadn't occurred to me before. It'd certainly be worth a shot! |
Ah, I remember now why that won't work. The issue is that, when we have a The need to use TLDR: I don't think there's an easy workaround here. Where it's an issue, I'm afraid that avoiding |
The code set the invocation's |
It would be great if |
The thought I had on this is we could special case a handful of very common signatures. Somewhat like the block trampoline, except maybe with the addition of handling some non-object types. If the selector is irregular, we resort to From New Relic's docs, the signatures on |
@kastiglione I'm not a big fan of that inconsistency. Although the current behavior is pretty shitty with regard to |
@buchananbryce I feel like this may be a fallacy. If there are that many frameworks that are causing problems that you can't special case them, then seems to me you have a larger problem on your hands. If there aren't that many, then why is it not feasible? Btw, Apple and WebKit both special case by bundle ID to work around problems, but of course that's not an apples to apples comparison. |
@jspahrsummers I'm just thinking of helping out RAC developers. It sucks, but at least subjects can be used as a workaround. |
You could fix this by replacing |
I presume something like that would work. Libffi has been mentioned a couple of times, but no serious discussion (that I've seen). |
libffi would probably work, yes, but it's also a large, scary, and fragile dependency (especially on iOS) to bring in. I generally prefer to rely upon built-in Cocoa tooling where possible. |
I assume there's been no changes on this on either side? Just ran into the same issue. We'll be reporting it to new relic, but it sounds like they aren't interested in changing it. |
The RAC problem is extremely hard (if not impossible) to fix without libffi. The suggested workaround is to use |
Yeah that's what we're doing. Just cumbersome. Love |
Hi @sprynmr. We're not opposed to adding special case support for RAC. We do have to consider the performance implications and how popular the framework is. Please do file a report / request so we've got your vote counted. |
@fightingmonk Noted. We sent our request along through proper channels. Thanks! |
I'm seeing this issue when using RACSignal *willDisappear = [self rac_signalForSelector:@selector(viewWillDisappear:)];
[[mySignal takeUntil:willDisappear] subscribeNext:^(id x){}]] |
I didn't investigate it deeply yet, but due to invocation swizzling in RAC and some internal behaviors in NewRelic (http://newrelic.com) agent cause application to froze right after launch. Apparently it is going into infinity loop:
I reported it to NewRelic as well with issue id 117914
The text was updated successfully, but these errors were encountered: