marnec
marnec7mo ago

runafter vs wrapper-action

Hi there, I'm wondering what is the suggested approach for the following scenario: an API endpoint that needs to perform a mutation, (optionally retrieve some data,) and the perform an operation over the network, like an httpcall. At the moment I have two different cases in which I'm adopting two different strategies: - I'm sending emails after storing an invitation record in convex using scheduler.runAfer(0, internal.emails.sendemail) from whitin the mutation that stores the invitation record - I'm sending push notification after storing a message in convex. I have a convex action that wraps (1) the mutation that stores the message; (2) the query to retrieve the push subscriptions; (3) the action to send the notifications. What would be the suggested approach for this kind of scenarios?
7 Replies
Convex Bot
Convex Bot7mo ago
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!
jamwt
jamwt7mo ago
the first approach is the common one, and the recommended one
jamwt
jamwt7mo ago
from the zen of convex
No description
marnec
marnecOP7mo ago
thanks
Waffleophagus
Waffleophagus2mo ago
Sorry to slightly resurrect an old thread, the AI in the #ask-ai suggested this thread. I have a call that my client calls to call an LLM, doesn't need a streaming response, just a "what's in this photo" call that is an action that I am calling directly from the client. This call is used by the client to fill out a form, and isn't directly stored in the database till the user approves the data from said form. I obviously do not wanna put API keys in the client (expo app) and am just calling the action. Given that there's no direct convex tables updated, in y'all's opinion is that an OK flow? Or would there be a better way to handle that?
export const parseOdometer = action({
args: {
imageBase64: v.string(),
},
handler: async (ctx, args) => {
// Check authentication
const identity = await ctx.auth.getUserIdentity()
const userId = identity?.subject as Id<"users">
if (!userId) {
const error: ParseError = {
type: ParseErrorType.AUTHENTICATION_ERROR,
message: "You must be logged in to use this feature",
}
throw new Error(JSON.stringify(error))
}

// Use Gemini to extract odometer reading
const odometerResult = await extractOdometerReading(args.imageBase64)
if (odometerResult.isErr()) {
throw new Error(JSON.stringify(odometerResult.error))
}

return odometerResult.value
},
})
export const parseOdometer = action({
args: {
imageBase64: v.string(),
},
handler: async (ctx, args) => {
// Check authentication
const identity = await ctx.auth.getUserIdentity()
const userId = identity?.subject as Id<"users">
if (!userId) {
const error: ParseError = {
type: ParseErrorType.AUTHENTICATION_ERROR,
message: "You must be logged in to use this feature",
}
throw new Error(JSON.stringify(error))
}

// Use Gemini to extract odometer reading
const odometerResult = await extractOdometerReading(args.imageBase64)
if (odometerResult.isErr()) {
throw new Error(JSON.stringify(odometerResult.error))
}

return odometerResult.value
},
})
jamwt
jamwt2mo ago
yeah, if the work is only in service of the current user, and it's okay if it doesn't complete if the browser session drops, it's okay to call it directly from the browser
Waffleophagus
Waffleophagus2mo ago
oh, its an expo app but yea, I see your point, hadn't thought of that weirdness The plan is to give the premium users a much cleaner flow that backgrounds things, how I found this to begin with. If a user closes the app while its parsing, that's on them I guess. ¯\_(ツ)_/¯ We'll see Went back and tested it, appears that since we're an expo app, as long as the user doesn't actively force kill the app, it'll still run while backgrounded, so I think we're good

Did you find this page helpful?