[Go] Service Weaver

์„œ๋น„์Šค ์œ„๋ฒ„๋Š” ๊ตฌ๊ธ€์—์„œ ์ง์ ‘ ๊ฐœ๋ฐœํ•œ ๋ถ„์‚ฐ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์šฉ ์„œ๋ฒ„ ํ”„๋ ˆ์ž„์›Œํฌ๋‹ค.
๊ทธ ๋ถ„์•ผ ์ตœ๊ฐ•์ž๋˜ Erlang OTP์™€ ํฌ์ง€์…˜์ด ๋น„์Šทํ•˜๋‹ค๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

์•„์ง ์ดˆ์ฐฝ๊ธฐ๋ผ ๋ฒ„์ „๋„ 0.3๋กœ ๋‚ฎ๊ณ , ๋ถˆ์•ˆ์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.




๊ธฐ๋ณธ ์š”์†Œ ์„ค์น˜

์šฐ์„  ํ”„๋กœ์ ํŠธ ๋งŒ๋“ค๊ณ , mod init์œผ๋กœ ์ดˆ๊ธฐํ™”ํ•ด์ค€ ๋‹ค์Œ์—

์ „์šฉ CLI๋ฅผ ์„ค์น˜ํ•œ๋‹ค.

go install github.com/ServiceWeaver/weaver/cmd/weaver@latest




ํ”„๋กœ์ ํŠธ ๊ตฌ์„ฑ

์†Œ์Šค์ฝ”๋“œ์™€ ํ•จ๊ป˜ Hello World ํ”„๋กœ๊ทธ๋žจ์„ ๊ตฌ์„ฑํ•ด๋ณด๊ฒ ๋‹ค.
HTTP ์„œ๋ฒ„๊ฐ€ ์•„๋‹Œ ์ผ๋ฐ˜ CLI ํ”„๋กœ๊ทธ๋žจ์ด๋‹ค.

์•„๋ž˜๋Š” ๋ฌธ์ž์—ด์„ ๋ฐ˜์ „์‹œํ‚ค๋Š” Reverse ํ•จ์ˆ˜๋ฅผ weaver์—์„œ ์š”๊ตฌํ•˜๋Š” ์œ„๋ฒ„ ์ปดํฌ๋„ŒํŠธ์˜ ํ˜•ํƒœ์— ๋งž์ถฐ ๊ตฌํ˜„ํ•œ ๊ฒƒ์ด๋‹ค.

package main

import (
	"context"

	"github.com/ServiceWeaver/weaver"
)

// Reverser component.
type Reverser interface {
	Reverse(context.Context, string) (string, error)
}

// Implementation of the Reverser component.
type reverser struct {
	weaver.Implements[Reverser]
}

func (r *reverser) Reverse(_ context.Context, s string) (string, error) {
	runes := []rune(s)
	n := len(runes)
	for i := 0; i < n/2; i++ {
		runes[i], runes[n-i-1] = runes[n-i-1], runes[i]
	}
	return string(runes), nil
}

์ผ๋‹จ์€ ์Šคํ”„๋ง์ด๋‚˜ Nest.js ๋“ฑ์—์„œ ๋‹ค๋ฃจ๋Š” DI, ์„œ๋น„์Šค ๋‹จ์œ„์™€ ๋Œ€์ถฉ ๋น„์Šทํ•˜๋‹ค๊ณ  ๋ณด๋ฉด ๋œ๋‹ค. ์‹ค์ œ๋กœ๋Š” ์•„์ฃผ ๋งŽ์ด ๋‹ค๋ฅด์ง€๋งŒ, ์ผ๋‹จ ์ง€๊ธˆ์€ ๊ทธ๋ ‡๊ฒŒ๋งŒ ์ดํ•ดํ•˜์ž.

์ €๋ ‡๊ฒŒ ์ •์˜ํ•ด๋†“๊ณ  ์œ„๋ฒ„ ์‹œ์Šคํ…œ์„ ํ†ตํ•ด ๊บผ๋‚ด์„œ ์“ฐ๊ฒŒ ๋œ๋‹ค.

์•„๋ž˜๋Š” ๋ฉ”์ธ ์†Œ์Šค์ฝ”๋“œ๋‹ค.

package main

import (
	"context"
	"fmt"
	"log"

	"github.com/ServiceWeaver/weaver"
)

func main() {
	// Initialize the Service Weaver application.
	ctx := context.Background()
	root := weaver.Init(ctx)

	// Get a client to the Reverser component.
	reverser, err := weaver.Get[Reverser](root)
	if err != nil {
		log.Fatal(err)
	}

	// Call the Reverse method.
	reversed, err := reverser.Reverse(ctx, "!dlroW ,olleH")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(reversed)
}

์ •์˜ํ–ˆ๋˜ reverse ํ•จ์ˆ˜๋ฅผ weaver ๋Ÿฐํƒ€์ž„์„ ํ†ตํ•ด ๊ฐ€์ ธ์˜ค๊ณ , ์‚ฌ์šฉํ•ด์„œ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋’ค์ง‘ํžŒ ํ…์ŠคํŠธ๋ฅผ ์ถœ๋ ฅํ•˜๋Š” ๋‹จ์ˆœํ•œ ํ”„๋กœ๊ทธ๋žจ์ด๋‹ค.

ํ•œ๋ฒˆ ์‹คํ–‰ํ•ด๋ณด์ž.

๋จผ์ € tidy๋กœ ์ข…์†์„ฑ์„ ์ดˆ๊ธฐํ™”ํ•ด์ฃผ๊ณ 

go mod tidy

weaver CLI๋กœ ์ •์˜ํ–ˆ๋˜ ์œ„๋ฒ„ ์ปดํฌ๋„ŒํŠธ์— ๋Œ€ํ•œ ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•ด์ค€๋‹ค.

weaver generate .

๊ทธ๋Ÿผ ์ด๋Ÿฐ์‹์œผ๋กœ "weaver_gen" ์†Œ์Šค์ฝ”๋“œ๊ฐ€ ์ถ”๊ฐ€๋  ๊ฒƒ์ด๋‹ค.
์ € ๋‚ด์šฉ์ด ์ค‘์š”ํ•œ๊ฑด ์•„๋‹ˆ๊ณ , ์ด๊ฒŒ ์ƒ์„ฑ๋˜์–ด์•ผ ์‹คํ–‰์ด ๋œ๋‹ค๋Š” ๊ฒƒ๋งŒ ์•Œ๋ฉด ๋œ๋‹ค.

๊ทธ๋Ÿผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ฐ„๋‹จํ•˜๋‹ค.

์—ฌ๊ธฐ์„œ ๋งŒ๋“ค๊ณ  ์‚ฌ์šฉํ•ด๋ณธ Reverser๊ฐ€ ๋ฐ”๋กœ ์œ„๋ฒ„์˜ ๊ทผ๊ฐ„์„ ์ด๋ฃจ๋Š” "์ปดํฌ๋„ŒํŠธ" ์‹œ์Šคํ…œ์ด๋‹ค.

๊ทธ๋ƒฅ ์ € ์ฝ”๋“œ๋งŒ ๋ณด๋ฉด ๋ณ„๊ฑฐ ์•„๋‹Œ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ผ ์ˆ˜ ์žˆ์ง€๋งŒ, ์ปดํฌ๋„ŒํŠธ๋Š” ์œ„๋ฒ„๋ฅผ ์„ค์ •ํ•˜๊ธฐ์— ๋”ฐ๋ผ์„œ ๊ทธ๋ƒฅ ํ•จ์ˆ˜๋กœ ๋™์ž‘ํ•  ์ˆ˜๋„, ์•„๋‹ˆ๋ฉด ๋ณ„๋„ ํ”„๋กœ์„ธ์Šค๋กœ ๋™์ž‘ํ•  ์ˆ˜๋„ ์žˆ๊ณ , ๋ณ„๋„์˜ ๋จธ์‹ ์—์„œ ๋™์ž‘ํ•˜๋„๋ก ํ•  ์ˆ˜๋„ ์žˆ๋‹ค!

ํ•˜๋‚˜์˜ ํ”„๋กœ์ ํŠธ ๋‹จ์œ„๋ฅผ ๋ณ„๋„์˜ ๋จธ์‹ ์—์„œ ๋™์ž‘ํ•˜๊ฒŒ ํ•˜๋Š” ํŽธ๋ฆฌํ•œ "๋ถ„์‚ฐ ์‹œ์Šคํ…œ"์ด ๋ฐ”๋กœ ์œ„๋ฒ„๊ฐ€ ์ง€ํ–ฅํ•˜๋Š” ๋ชฉํ‘œ๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค.




HTTP ์„œ๋ฒ„ ๋งŒ๋“ค๊ธฐ

์ด๋ฒˆ์—๋Š” ๊ทธ๋ƒฅ ์ฝ˜์†” ์ฐ๊ณ  ์ฃฝ๋Š”๊ฑฐ ๋ง๊ณ  ์ œ๋Œ€๋กœ๋œ ์„œ๋ฒ„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“ค์–ด๋ณด๊ฒ ๋‹ค.

์œ„๋ฒ„์—์„œ ๋”ฑํžˆ ๋Œ€๋‹จํ•œ ๊ตฌ์กฐ๋ฅผ ์ œ๊ณตํ•˜๋Š”๊ฑด ์•„๋‹ˆ๊ณ , API ์ •์˜๋Š” ๊ธฐ๋ณธ http ๋ชจ๋“ˆ๋กœ ํ•˜๋ฉด ๋œ๋‹ค.

์ „๋‹ฌ๋ฐ›์€ name์œผ๋กœ ์ธ์‚ฌ๋ฅผ ํ•ด์ฃผ๋Š” "/hello"๊ณผ ์œ„์—์„œ ์ •์˜ํ–ˆ๋˜ reverse ํ•จ์ˆ˜๋กœ ๋’ค์ง‘ํžŒ ๋ฌธ์ž์—ด์„ ๋ฐ˜ํ™˜ํ•ด์ฃผ๋Š” "/reverse" API๋ฅผ ์ •์˜ํ•ด๋ดค๋‹ค.

package main

import (
	"context"
	"fmt"
	"log"
	"net/http"

	"github.com/ServiceWeaver/weaver"
)

func main() {
	// Initialize the Service Weaver application.
	ctx := context.Background()
	root := weaver.Init(ctx)

	// Get a client to the Reverser component.
	reverser, err := weaver.Get[Reverser](root)
	if err != nil {
		log.Fatal(err)
	}

	// Get a network listener on address "localhost:12345".
	opts := weaver.ListenerOptions{LocalAddress: "localhost:12345"}
	listener, err := root.Listener("hello", opts)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("hello listener available on %v\n", listener)

	// Serve the /hello endpoint.
	http.HandleFunc("/hello", func(writer http.ResponseWriter, request *http.Request) {
		name := request.URL.Query().Get("name")
		fmt.Fprintf(writer, "Hello, %s!\n", name)
	})

	// Serve the /reverse endpoint.
	http.HandleFunc("/reverse", func(writer http.ResponseWriter, request *http.Request) {
		reversed, err := reverser.Reverse(request.Context(), request.URL.Query().Get("text"))
		if err != nil {
			http.Error(writer, err.Error(), http.StatusInternalServerError)
			return
		}
		fmt.Fprintf(writer, "%s", reversed)
	})

	http.Serve(listener, nil)
}

๊ทธ๋Ÿฌ๊ณ  ์‹คํ–‰ํ•˜๋ฉด

์ด๋Ÿฐ์‹์œผ๋กœ ๋œฌ๋‹ค.


์ž˜ ๋„๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

์œ„๋ฒ„ ์„œ๋น„์Šค๊ฐ€ ๋„๋Š” ๊ฒƒ์€ weaver CLI๋ฅผ ํ†ตํ•ด์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
์ด๋Ÿฐ์‹์œผ๋กœ ๋œฌ๋‹ค.



์ฐธ์กฐ
https://serviceweaver.dev/
https://opensource.googleblog.com/2023/03/introducing-service-weaver-framework-for-writing-distributed-applications.html?m=1
https://serviceweaver.dev/docs.html