0

I have a GO Post API endpoint with a somewhat time-consuming task in the handler (time can be 2 minutes even, when I running it locally).

In my FE I call the API once and it triggers only once (in the network tab, there are no multiple requests) (1). The running time of the API call differs since it runs according to some dynamic data. But on the API side, the call takes some time and succeeds, but doesn't send a response (still Pending in FE side). Then right away the handler runs again (still Pending in FE side) and the logic runs again. So, due to logic, since it's run already, it fails. Then that response is returning as the response for the request from FE (1) . So, the logic is a success, and DB is updated, but the response sends an error.

Does this due to a time-out issue? If so, how can I get this fixed?

I use go-chi as the GO framework and react for FE.

r := chi.NewRouter()

r = helpers.AttachLoggerMiddleware(r, pretty)
r.Route("/apps", func(r chi.Router) {
    r.Post("/{id}/clone", service.Clone)
}


func (s *Service) Clone(w http.ResponseWriter, r *http.Request) {     
    fmt.Println("Calling Clone !!")
    //logic
}

This is somewhat of a sample of how the API method configured

Thidasa Pankaja
  • 930
  • 8
  • 25
  • 44

1 Answers1

0

You should redesign your approach to use Long polling mechanism, use WebSosket or JSON streaming also will be an option.

A bit explanation:

You have a time-consuming task (takes 2 minutes, pretty sure it can take even more if your app will have more load). So, if you will use a simple Request-Respons approach, you will have an error because of timeout issues.

Because of that, using of proposed approaches will be better for your case.

Let's look at the WebSocket example:

In your go code, you will have something like(it's just an example to catch up an idea, I don't know chi and use github.com/gorilla/websocket and vanilla net/http but I'm pretty sure that you can do the same with chi):

package main

import (
    "fmt"
    "github.com/gorilla/websocket"
    "log"
    "net/http"
    "time"
)

var upgrader = websocket.Upgrader{
    ReadBufferSize:  1024,
    WriteBufferSize: 1024,
}

func main() {
    http.HandleFunc("/ws", wsHandler)
    
    panic(http.ListenAndServe(":8080", nil))
}

func wsHandler(w http.ResponseWriter, r *http.Request) {
    conn, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        log.Println(err)
        return
    }
    
    if err != nil {
        http.Error(w, "Could not open websocket connection", http.StatusBadRequest)
    }
    
    go echo(conn)
}

func echo(conn *websocket.Conn) {
    defer conn.Close()
    m := ""
    
    err := conn.ReadJSON(&m)
    if err != nil {
        fmt.Println("Error reading json", err)
    }
    
    // receive some data from your reactjs
    fmt.Printf("Got message: %#v\n", m)
    
    om := struct {
        mes string
    }{
        mes: "Send to client",
    }
    
    // send some data
    if err = conn.WriteJSON(om); err != nil {
        fmt.Println(err)
    }
    
    // do some work in 2 min
    time.Sleep(120 * time.Second)
    
    // send some data
    if err = conn.WriteJSON(om); err != nil {
        fmt.Println(err)
    }
}

In your react js app you will have something like:

import React, { useState } from "react";

function  App() {
  let isDone = false;
  const messages = []
  const ws = new WebSocket("wss://localhost:8080/ws");

  const apiCall = {
    mes: "Your json for server" 
  };

  ws.onopen = (event) => {
    ws.send(JSON.stringify(apiCall));
  };

  ws.onmessage = function (event) {
    const json = JSON.parse(event.data);
    messages.push(json)
    } catch (err) {
      console.log(err);
    }
  };
  
  ws.onclose = function (event) {
    isDone = true
  };



  const mess = messages.map((item) => {
    return (
      <div>
        <p> {item}</p>
      </div>
    );
  });

  return (
       <div>
           <div>{mess}</div>
           <div> is work done?: {isDone}</div> 
       </div> 
   );
}

export default  App;

In this example, we send some info to the server and start waiting when work will be finished(isDone = true when ws closed), meanwhile receiving some messages(maybe it's non needed in your case).

Same for implementation of this idea with Long polling and JSON streaming (I think you easily find something on the internet:) )

Danil Perestoronin
  • 1,063
  • 1
  • 7
  • 9