Correct procedure to send a message to a client through websockets in PHP?

97 Views Asked by At

I am developing a Symfony 6 project, in one of the screens I want to start executing a .jar whenever a button is pressed. I have manage to execute it asynchronously, but I have not being capable of informing to the client that the process has finish, therefore I decided to make use of websockets. I started by making a small design to test them, for some reason the client only connects to the web server, but it does not to receive any message.

This is my javascript file

// WebSocket setup
const socket = new WebSocket('ws://localhost:8080');

socket.addEventListener('open', event => {
    console.log('Connected');
});

socket.addEventListener('message', event => {
    const message = JSON.parse(event.data);
    if (message.type === 'progress') {
        console.log(message.text);
    }
});

socket.addEventListener('close', event => {
    console.log('Connection closed');
});

// Fetch request
document.getElementById('upload-button').addEventListener('click', () => {
    const fileInput = document.getElementById('zip-file');
    
    const formData = new FormData(); // Create a new FormData object
    formData.append('del-file', fileInput.files[0]); // Append the selected file to the FormData
  
    fetch('/start-process', {
        method: 'POST',
        body: formData, // Send the FormData as the request body
    })
    .then(response => response.json())
    .then(data => console.log(data))
    .catch(error => console.error('Error:', error));
});

This would be the function called when the button is pressed

/**
     * @Route("/start-process", name="start_process", methods={"POST"})
     */
    public function startProcess(Request $request, MessageBusInterface $messageBus, WebSocketServer $webSocketServer): JsonResponse
    {
        // Start the asynchronous background job
        $message = ['type' => 'progress', 'text' => 'Job started'];
        $webSocketServer->broadcast(json_encode($message));

        // Simulate background job
        sleep(2); // Simulate work
        $message = ['type' => 'progress', 'text' => 'Job in progress...'];
        $webSocketServer->broadcast(json_encode($message));
        sleep(2); // Simulate work
        // Simulate background job completion
        $message = ['type' => 'progress', 'text' => 'Job completed'];
        $webSocketServer->broadcast(json_encode($message));
        return $this->json(['message' => 'Process finished']);
    }

This is the only output that I receive in the console log

1

There are 1 best solutions below

0
Tim Roberts On

I'm typing this up as an answer because it is long.

The fundamental disconnect you have here is that your websocket is being opened in a different process from your web server. If you expect the two to interact, they have to be handled in the same process. That might mean mixing the two packages, so you can respond to both websocket requests and web server requests. And note that you'll need some way to associate the two; you cannot assume that you only have one client, so you might have multiple web sockets that you'll need to assign to the proper web session.

Allow me to propose an alternate strategy for what you're talking about. Instead of creating a web socket, have a Javascript loop in your front-end that polls the back end every second or so using normal fetch requests. That, then, becomes just another API for your back-end to handle, to return the current status of the operation.

This is a very common pattern for handling long-running background tasks, and is way simpler than managing a web socket. You may even be able to find code for this online.