don't stop believing

Goroutines inside a middleware 본문

Golang/Gin

Goroutines inside a middleware

Tongchun 2019. 3. 14. 17:55

Server 개발 시 비동기로 처리해야 할 때가 있습니다. 저 같은 경우 redis에 쓰기 처리를 할때는 보통 비동기로 처리하기도 합니다.

go에서 비동기 처리 할 때는 goroutine을 사용합니다.

https://github.com/gin-gonic/gin#goroutines-inside-a-middleware


goroutine을 사용할 때 중요한 부분은 gin의 원본 context를 사용하면 안되고 읽기 전용으로 복제해서 사용해야 합니다.

When starting new Goroutines inside a middleware or handler, you SHOULD NOT use the original context inside it, you have to use a read-only copy.


바로 코드를 확인하면 아래와 같습니다.

package main

import (
	"log"
	"time"

	"github.com/gin-gonic/gin"
)

func setupRouter() *gin.Engine {
	// Disable Console Color
	// gin.DisableConsoleColor()
	r := gin.Default()

	r.GET("/long_async", longAsync)
	r.GET("/long_sync", longSync)

	return r
}

func longAsync(c *gin.Context) {

	// create copy to be used inside the goroutine
	cCp := c.Copy()

	go func() {
		// simulate a long task with time.Sleep(). 5 seconds
		time.Sleep(5 * time.Second)

		// note that you are using the copied context "cCp", IMPORTANT
		log.Println("Done! in path " + cCp.Request.URL.Path)
	}()

}

func longSync(c *gin.Context) {

	// simulate a long task with time.Sleep(). 5 seconds
	time.Sleep(5 * time.Second)

	// since we are NOT using a goroutine, we do not have to copy the context
	log.Println("Done! in path " + c.Request.URL.Path)
}

func main() {
	r := setupRouter()
	// Listen and Server in 0.0.0.0:8080
	r.Run(":8080")
}

goroutine을 사용한 async 처리와 그렇지 않은 sync 처리를 비교할 수 있습니다.

실행하고 두 route를 호출하면 아래와 같은 결과가 나옵니다.

$ go run example/server.go 
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.

[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
 - using env:	export GIN_MODE=release
 - using code:	gin.SetMode(gin.ReleaseMode)

[GIN-debug] GET    /long_async               --> main.longAsync (3 handlers)
[GIN-debug] GET    /long_sync                --> main.longSync (3 handlers)
[GIN-debug] Listening and serving HTTP on :8080
[GIN] 2019/03/14 - 15:51:58 | 404 |         876ns |             ::1 | GET      /login-asinc
[GIN] 2019/03/14 - 15:52:10 | 200 |       3.486µs |             ::1 | GET      /long_async
2019/03/14 15:52:15 Done! in path /long_async
2019/03/14 15:53:05 Done! in path /long_sync
[GIN] 2019/03/14 - 15:53:05 | 200 |   5.00426148s |             ::1 | GET      /long_sync

/long_async를 호출하면 아래와 같이 15:52:10초에 response가 리턴되고 groutine은 그보다 5초 후인 15:52:15에 종료됩니다.

[GIN] 2019/03/14 - 15:52:10 | 200 |       3.486µs |             ::1 | GET      /long_async

2019/03/14 15:52:15 Done! in path /long_async

/long_sync의 경우 5초를 기다린 다음 response가 리턴됩니다.

2019/03/14 15:53:05 Done! in path /long_sync

[GIN] 2019/03/14 - 15:53:05 | 200 |   5.00426148s |             ::1 | GET      /long_sync

비동기 처리에 사용하면 좋습니다.


'Golang > Gin' 카테고리의 다른 글

Bind Uri  (0) 2019.03.14
How to write log file  (0) 2019.03.14
Only Bind Query String  (0) 2019.03.09
Bind Query String or Post Data  (0) 2019.03.09
Model binding and validation  (0) 2019.03.06
Comments