Responder con mensaje mientras se generan los archivos
Tengo un servicio donde los usuarios pueden exportar datos a un archivo de Excel que genero para ellos en mi servidor backend. A veces, estas exportaciones pueden ser grandes. Por lo tanto, con el objetivo de tener en cuenta la experiencia de usuario, quiero confirmar que el servidor recibe la solicitud y responderá que los documentos se están generando y les serán enviados por correo electrónico una vez finalizados.
Este es un ejemplo básico de lo que tengo hasta ahora.
Código:
func generateDocx(n int, wg *sync.WaitGroup) {
defer wg.Done()
for i := 0; i < 10; i++ {
amt := time.Duration(rand.Intn(250))
time.Sleep(time.Millisecond * amt)
fmt.Println("Exportando:", n, "Número del documento:", i)
}
}
func ExportService() {
wg := &sync.WaitGroup{}
for i := 0; i < 10; i++ {
wg.Add(1)
go generateDocx(i, wg)
}
wg.Wait()
// enviar correo electrónico al usuario después de que se generen todos los documentos
fmt.Println("Enviando correo electrónico de que los documentos están listos")
}
func main() {
finish := make(chan bool)
// var input string
// fmt.Scanln(&input)
router := mux.NewRouter()
type Reply struct {
Title string
Message string
}
router.HandleFunc("/export", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
fmt.Println("comenzando generación")
ExportService()
json.NewEncoder(w).Encode(&Reply{
Title: "Generando",
Message: "Se están generando sus archivos, recibirá un correo electrónico cuando los archivos estén listos.",
})
fmt.Println("respondido")
})
log.Fatal(http.ListenAndServe(":8080", router))
<-finish
}
Cuando se alcanza el punto final:
comenzando generación
Exportando: 8 Número del documento: 0
Exportando: 6 Número del documento: 0
Exportando: 9 Número del documento: 0
Exportando: 6 Número del documento: 1
Exportando: 4 Número del documento: 0
Exportando: 3 Número del documento: 0
Exportando: 2 Número del documento: 0
Exportando: 1 Número del documento: 0
Exportando: 3 Número del documento: 1
Exportando: 0 Número del documento: 0
Exportando: 6 Número del documento: 2
etc...
Enviando correo electrónico de que los documentos están listos
respondido
Incluso mientras el WaitGroup está en ExportService y no devuelve nada al controlador, la respuesta aún espera que se complete la generación antes de responder con el mensaje de éxito.
Quiero decir que entiendo la concurrencia en Go, pero evidentemente me falta algo. ¿Alguien puede ayudarme?
davy.ai
Parece que la implementación actual de
ExportService()
está bloqueando el hilo principal hasta que se generen todos los documentos y se envíe el correo electrónico. Una solución a esto podría ser mover la llamada aExportService()
a una gorutina separada y hacer que devuelva un canal que envíe un mensaje cuando los documentos estén listos para ser enviados por correo electrónico.Aquí tienes un ejemplo:
En este ejemplo, creamos un nuevo canal
done
y se lo pasamos aExportService()
como argumento. Dentro deExportService()
, creamos un nuevo grupo de esperawg
y agregamos las gorutinas para generar los documentos. Cuando se generan todos los documentos, enviamos un mensaje en el canaldone
para indicar que los documentos están listos para ser enviados por correo electrónico.De vuelta en el manejador HTTP, creamos una nueva gorutina para esperar a que el canal
done
reciba un mensaje que indique que los documentos están listos. Una vez recibido, podemos enviar un correo electrónico al usuario. Mientras tanto, el manejador responde de inmediato con un mensaje de éxito informando al usuario que los documentos se están generando.Al utilizar canales, podemos hacer que la generación de los documentos y el envío del correo electrónico ocurran de forma concurrente sin bloquear el hilo principal, lo cual permite una mejor experiencia de usuario.