requestId access
Is there a way to gain access to the
requestId
in the context? I've dug through the convex-js code and it seems like something might be stubbed out, but I can't seem to figure how to get at it28 Replies
Thanks for posting in <#1088161997662724167>.
Reminder: If you have a Convex Pro account, use the Convex Dashboard to file support tickets.
- Provide context: What are you trying to achieve, what is the end-user interaction, what are you seeing? (full error message, command output, etc.)
- Use search.convex.dev to search Docs, Stack, and Discord all at once.
- Additionally, you can post your questions in the Convex Community's <#1228095053885476985> channel to receive a response from AI.
- Avoid tagging staff unless specifically instructed.
Thank you!
No, it can't be accessible in queries because that would always break the cache. Is there something you want to do with this for logging? We can add ways to log the value, but we can't make it available in a request.
Trying to figure cross-api tracing. I am using portkey.ai, it has the ability to track traces and spans, also wanted to tool the same for sentry, and use the same traces/spans for tracking from the convox request on up.
I tried doing this manually, but the context object doesn't seem to persist between the ctx.run(mutation|quer|action) calls, so if I set a custom context that creates a traceId, that trace id wont be persisted to nested runQuery statements.
normally in convex this would be fine because logging groups by requestId, but doesn't work cross-service as effectively.
you could add request ids that get passed to runQuery/etc. with custom functions https://stack.convex.dev/custom-functions
Customizing serverless functions without middleware
Re-use code and centralize request handler definitions with discoverability and type safety and without the indirection of middleware or nesting of wr...
'twas the first thing I tried. problem is, context does not seem to be carried through to child calls. I'm a core developer on moleculerjs which has a similar concept, make a series of calls
call a -> call b -> call c
the thread id from call a will be passed in the context of b & c, the spans for b will reference the span of a as its parent, the span of c, the spand of b as the parent.
Trying to do this using custom functions I found, that in that same pattern, the threadId of a is not passed to the context of b, maybe I missed something?
you could pass it through as an argument to nested calls
(idk why claude thought that the first argument to runMutation/runQuery should be called
name
)1. Does passing around the requestId effect query cache?
2. With this approach, if we pass the modified context (runMutation / runQuery) to action retrier, then the internal component functions fails with argument validation as they don't allow requestId.
ex: const runId = await ctx.runMutation(this.component.public.start, {
As a workaround, I tried not to add these new parameters to action retrier functions, but I'm not sure if this is the right way. Is there a better way to handle this?
3. Also as Tom mentioned, it would be great if you can expose the requestId in query / mutation and action (not in request args may be in ctx?) something similar to httpAction (request.headers.get("convex-request-id"))
It probably shouldn't be exposed, because that will bust the query cache. But it could be logged, and you could set up log streams to another service. Are you using the Convex Sentry integration?
Ah I see cross-service, yeah we could allow access in actions so that you could include it in a
fetch()
. But Lee's suggestion sounds like the way to go for accepting an ID from another serviceMy plan was to use an HTTP webhook to send the data to ClickHouse. Is requestId already available in the log streams?
Regarding the approach Lee suggested - passing data using ctx, runQuery, or runMutation—would this cause the query cache to be invalidated? While the custom query accepts requestId as part of the arguments, the input function ultimately returns empty arguments in its return value.
Yes, any arguments to a function are included in the cache key.
@ballingt for Moleculer we compute cache keys the same way, we allow the passing of meta information between nested calls which are not calculated into the cache key, as it is supposed to be non actionable information, is that a feature that could be added?
We want to be very careful about this, as soon as we allow developers to break the rules there's a lot more they need to worry about.
But yeah this is totally possible
What are the conventions around these request IDs? It feels safer if it's a common standard, like a specific header name
could be another set of arguments, which developers are not allowed to access in Convex functions, but will be passed on
Moleculer looks cool!
Here is how I would be handle it the moleculer framework (which has a similar nested context call)
this hits moleculer service endpoint and constructs the following context object
so in this case, the meta from the context object in the
endpoint
. .... er.. endpoint is passed to some.other.service
, so that service has access to the same span trace information, the params are still used to calculate the cache
obviously this wouldn't be backwards compatible with convex's api, but you could achieve it by something like
by allowing for an additional argument in useQuery, we could achieve something non-breaking, and the handler functions could also optionally use the meta arg as well down the chain. this means when I use something like portkey.ai through convex actions, I can pass the trace and span to portkey which has its own trace logging, and I can trace a user request, including all api requests made by that user (in apis that support trace logging or can log to something like sentry) making it easy to trace a single user interaction through all requests cross/service/api
and you have the advantage of passing information that will differ with every requiest (such as a trace id) in such a way it never breaks caching if the params that would mutate the request are equal.The change I'd make is not exposing
ctx.meta
to userspace in queries and mutations, you never get to touch those unless you're in an action — but yeah they can be passed along
and it's fine to log themhrm
could you access them from a helper, i.e., if you wanted to instrument every query to look for a trace, and wrap a sentry call around the handler?
much like building a customContext
not for queries and mutations, you can't call sentry from those anyway
but you can log them, we've got log streams for processing those https://docs.convex.dev/production/integrations/log-streams/
ah, queries and mutation's can make network calls:? (I've never actually tried it, but makes sense)
no they can't
it'd be useful to know concretely what services you want to integrate with or what tracing formats you need — some of that may be better done at the "kernel" (platform) level
Convex actions use a custom but compliant (that's the goal) JavaScript runtime, so you can do totally custom logging there, run Molecular, etc.
but queries and mutations can't do anything nondeterministic, and any input needs to be part of the query key so we can protect the integrity of the cache
we'd like them to be able to run as many npm packages as possible, but if it's something meta like tracing it might be better to make it look more like the sentry integration, where it's all handled in Rust
Okay. I have a nextjs app, that has a SPA component to it. Convex drew me in after messing around with supabase, and finding that convex did a better job of getting me close to good offline support, which supabase is a pain to do (but its doable). I'm not using moleucler for the same reason. What I want insights to is:
user action -> calls mutation/query/action -> calls subquery -> mutation/action etc
the ability to ship the trace from the user interaction (i.e. click a submit button) to the final result and ship that information to sentry, including performance metrics , exceptions caught, etc. a lot of this is captured in convex's logs, but those logs dont capture data from other outside services, i.e. an LLM run
Sentry (or the like) provides a single place to coalate a trace cross service/api into one view
so your not having to cross reference a dozen different places in a complex flowDoes the current Convex Sentry integration get you from browser button press to mutation to action, but no further? not to query response (because request IDs aren't tracked through DB dataflow) and not to external service calls i.e. LLM (because the request ID isn't available in actions to do a fetch with)?
it only handles exceptions
at least on the convex end
oh interesting, I thought it gave spans too
not that I have found
ok that all makes sense
only traces I am getting are from the nextjs end
I am getting exceptions from convex though
I can see if it has span info init
I think there are log streams with some of this info
but absolutely agree a full tracing solution is important here
yeah, trace ids are not being sent
And either it should all work together, say we make you use Sentry or Honeycomb or otel format or whatever, or you want to ability to pass in arguments that aren't part of the cache key
You might start with passing in your own request id but not using them in queries that you need good caching for
mutations and actions can't be cached, so no cost there
and you're not going to be able to trace from mutation to query invalidation anyway
eg a mutation changes a db row which triggers a subscribed query to produce a new result