For MRs it looks like we spend a lot of time keeping refs around and fetching them. @dbalexandre and I discussed this a bit in the context of the GH importer, and it should be possible to remove or batch some of those. (Serialising diffs to YAML will also be painful, but harder to fix.)
For issues and MRs, I wonder if we could move at least the cross-reference creation to a worker, like we do for notes with the NewNoteWorker. It looks like that would shave some time off 'for free':
MergeRequest#fetch_ref fetches a ref using git fetch. Using rugged.references.create (as is done by Repository#keep_around) might be faster when an MR's source and target project are the same.
As I said before, we could defer create_cross_references! and friends to a NewIssuableWorker, like we have for notes.
@smcgivern I am not sure a general NewIssuableWorker is the best approach. When I see the after_create for Merge requests and Issues they differ quite a lot.
We could obviously solve it using a condition or could create methods like EventService#open_issuable (same for notification_service and todo_service) and solve it there but maybe we should consider creating separate workers for merge requests and issues. WDYT?
Oh now I see you considered moving only issuable.create_cross_references!(current_user). I'd suggest moving the whole after_create + creating cross references
I think we still want to create todos in the request if we can, and probably resolve the discussions. Events, user agent details, and notifications can probably wait though.
I think I found the culprit, at least for merge requests - we run a fetch to make sure a commit is around on both #new and #create, and that can take around :siren: 30 SECONDS :siren:
@jneen good catch! I think we could do that, or check if self.project == other.project. @DouweM might have a strong opinion on which is better; I think the path check is probably fine, but there might be edge cases.
(I mentioned git fetch above, but more in the context of #create, where we also do this to ensure that the ref is prevented from being GCed, and we could just create the ref directly when we're not crossing forks. @godfat fixed that in https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/13416)