W
Wasp-langβ€’4mo ago
kancur

Using actions inside workers - is it possible?

Hey guys! I'm trying to use an action, imported like this:
import markTodoAsDone from '@wasp/actions/markTodoAsDone.js';
import markTodoAsDone from '@wasp/actions/markTodoAsDone.js';
inside a worker, defined inside server/workers/doSomething.ts The markTodoAsDone action seems to work fine on the client, but I'm not sure if I can use it inside a worker too? It seems it's missing a context.
Expected 2 arguments, but got 1.
An argument for 'context' was not provided.
Expected 2 arguments, but got 1.
An argument for 'context' was not provided.
Is this a natural limitation of how workers work? Or should I be able to use an action there as well? Thanks πŸ™‚
9 Replies
kancur
kancurβ€’4mo ago
The point of using an action was to receive a UI update on the client (to invalidate the react-query cache basically). If I edit the db directly from the job, this doesn't update the UI on the client. I can manually provide an argument for context, but in that case, well, I'm missing the context, like User.
martinsos
martinsosβ€’4mo ago
Ok, so if your job does an edit to the database, that change won't be picked up by the client automatically, you are right. It will, of course, if client is refreshed, but it won't be "pushed" to the client. While we are considering adding some direct support for that in Wasp in the future, for now, if you want that, your bet is to use sockets (Wasp has some support for websockets!) to send a message from the server to the client, and then you can react to that message on the client and update the UI if you wish. In general, calling actions from Jobs should be possible though! Yeah true, they are missing context, but you can construct one, if you have means to. The problem is, you can't really give the action a User, when Job is not being run by User, it is being run by Wasp, to put it that way. If there was logic in the action you wanted to reuse from Job, what I would do in this case is create a function for that logic, normal JS function somewhere in your server code, I would call it function X, and then your action can call call that function X inside it, and also your job can call that same function X. That way you can share a lot of logic, as much as you want.
kancur
kancurβ€’4mo ago
Okay, thanks a lot for the insight! πŸ™‚ I'll take a closer look at the websockets support in wasp πŸ™‚
martinsos
martinsosβ€’4mo ago
Great, and let me know if something is not clear / is cofusing -> I can try to help, or we can maybe even improve the docs if needed!
kancur
kancurβ€’4mo ago
Thanks, I might have one. I understand that you can get the io object inside webSocketFn like this (copied from docs):
export const webSocketFn: WebSocketFn = (io, context) => {
io.on('connection', (socket) => {
const username = socket.data.user?.email || socket.data.user?.username || 'unknown'
console.log('a user connected: ', username)

socket.on('chatMessage', async (msg) => {
console.log('message: ', msg)
io.emit('chatMessage', { id: uuidv4(), username, text: msg })
})
})
}
export const webSocketFn: WebSocketFn = (io, context) => {
io.on('connection', (socket) => {
const username = socket.data.user?.email || socket.data.user?.username || 'unknown'
console.log('a user connected: ', username)

socket.on('chatMessage', async (msg) => {
console.log('message: ', msg)
io.emit('chatMessage', { id: uuidv4(), username, text: msg })
})
})
}
But how do I use it elsewhere on the server? Where do I get it from? For example when I want to emit an event from the worker, how do I access the io? I can't find it in the docs thanks! πŸ™‚ On the frontend, you can use useSocket hook to get the socket instance, but how do I get it on the backend? in my worker, or elsewhere on the backend, I would like to emit an event like io.emit('someMessage', {}); But I don't really have access to io outside of webSocketFn . Do you have some example please? πŸ™‚
miho
mihoβ€’4mo ago
Hey @kancur I have some bad and some good news πŸ˜„ We know about this issue: https://github.com/wasp-lang/wasp/issues/1289 -> you can't get the io instance outside of the init function easily. You could hack it like this: - in the file where you have your init function create a "global" variable that you export from that file. Let's call it let ioInstance = undefined - then set that ioInstance to the io instance you have inside of the init function - elsewhere in your codebase, import the ioInstance and use it πŸ™‚
GitHub
Enable using the Websocket server inside of server-side code outsid...
Right now, the initialized server is not exposed or documented for the user to use. For example, when somebody likes a post, it might trigger something and a notification is sent over the socket.
miho
mihoβ€’4mo ago
Please report back if this worked for you, if not, we'll help you further πŸ™‚
kancur
kancurβ€’4mo ago
Thanks! I thought about that workaround, but assumed there must be a better way πŸ˜„ glad you know about it, will report back after weekend. Thank for you help πŸ™‚ Oh, I forgot to report here, the workaround worked fine, thanks! πŸ™‚
miho
mihoβ€’4mo ago
Great to hear that! We'll work on provide 1st party support soon πŸ˜„