LA_
LA_

Reputation: 20409

How to wait for callback function return?

I have the following code:

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  player.Exec(command, func(response map[string]interface{}){
    if response["statusCode"]==float64(0) { // ok
      w.Write([]byte(response["statusMessage"].(string)))
      player.SendMessage("<b>"+response["statusMessage"].(string)+"</b>")
      fmt.Println("playerExec: "+time.Now().Format("20060102150405"))
    } else { // failed to process
      w.WriteHeader(http.StatusBadRequest) // 400
      w.Write([]byte(response["statusMessage"].(string)))
      player.SendMessage(response["statusMessage"].(string))
    }
  })
  // Time.Sleep(Time.Seconds*2)
  fmt.Println("cmd: "+time.Now().Format("20060102150405"))   
})

processing of player.Exec() takes some time (since it initiates WebSocket connection), so the callback function is called after some time (see proofs below). It is late, so I see the following error:

http: superfluous response.WriteHeader call from main.main.func1.1

Also, when I open the '/' page in the browser, I see no content. If I add Time.Sleep() to my code (see the commented line), then I see the content. The Exec() code is here.

The log shows the following -

cmd: 20200612192659
playerExec: 20200612192659

Is there any way to wait for the callback function return?

Upvotes: 0

Views: 1320

Answers (2)

Tarun Khandelwal
Tarun Khandelwal

Reputation: 491

Yes, you can use sync.WaitGroup as follows:

wg := sync.WaitGroup{}

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  wg.Add(1)  // add a waitgroup before calling the async function
  player.Exec(command, func(response map[string]interface{}){
    defer wg.Done()  // release when this function returns
    if response["statusCode"]==float64(0) { // ok
      w.Write([]byte(response["statusMessage"].(string)))
      player.SendMessage("<b>"+response["statusMessage"].(string)+"</b>")
      fmt.Println("playerExec: "+time.Now().Format("20060102150405"))
    } else { // failed to process
      w.WriteHeader(http.StatusBadRequest) // 400
      w.Write([]byte(response["statusMessage"].(string)))
      player.SendMessage(response["statusMessage"].(string))
    }
  })
  wg.Wait()  // this will block until all the resources are released
  fmt.Println("cmd: "+time.Now().Format("20060102150405"))   
})

Upvotes: 2

poWar
poWar

Reputation: 825

http: superfluous response.WriteHeader call from main.main.func1.1

You will see this if you do a WriteHeader after you have already written something to the response via Write. That's why WriteHeader is extra or superfluous.

As of waiting for your exec to be done, you can use waitgroup in your closure.

wg.Wait() will wait until your exec callback has returned

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  var wg sync.WaitGroup
  wg.Add(1)
  player.Exec(command, func(response map[string]interface{}){
    defer wg.Done()
    if response["statusCode"]==float64(0) { // ok
      w.Write([]byte(response["statusMessage"].(string)))
      player.SendMessage("<b>"+response["statusMessage"].(string)+"</b>")
      fmt.Println("playerExec: "+time.Now().Format("20060102150405"))
    } else { // failed to process
      w.WriteHeader(http.StatusBadRequest) // 400
      w.Write([]byte(response["statusMessage"].(string)))
      player.SendMessage(response["statusMessage"].(string))
    }
  })

  wg.Wait()

  // Time.Sleep(Time.Seconds*2)
  fmt.Println("cmd: "+time.Now().Format("20060102150405"))   
})

Upvotes: 0

Related Questions