iT邦幫忙

2026 iThome 鐵人賽

DAY 13
0
Software Development

從零開始打造 Redis:以 Go 建立 Production Ready 應用程式 系列 第 14

[Day 14] 資料持久化(中): Middleware

  • 分享至 

  • xImage
  •  

在實現了 service.(AOF) 之後,我們需要思考如何優雅地使用這個介面。

誠然,直接在 SET 指令裡注入這個服務,並且當寫入 repo.(*mapStorage) 時直接把指令寫入 AOF 這確實是個辦法,只是這很不優雅--如此一來,違背了 ./internal/serivce/cmd/ 的設計初衷,正因為想要專注在指令功能上的開發才使用工廠模式,這麼做就像走了回頭路。

Middleware 中介層

在「請求 - 回應」的模型中,常常會使用到 Middleware(中介層) 設計模式,最典型的就是資源管理類的服務:

請求 -> 身份驗證中介層(Authenticator) -> 資源操作 ->  審計記錄中介層(Audit) -> 回應

在資源操作前,通常會先驗證身份,並且確認該身份有操作的權限(Authentication 與 Authorization),然後在資源操作之後,還需要記錄這次操作的情況,未來若有什麼問題可以追責或恢復。

在資料持久化的場景中,我們可以想像以下流程:

RESP 請求 -> Storage 操作 -> AOF Writer 中介層 -> 回應

Go 中的 Middlware

在 Go 中設計 Middleware 模式,通常會用 func(HandlerFunc) HandlerFunc

註:這邊本來有一個 Code Block,但是因為 ithome 的 cloudflare 規則擋掉了所以存不進來,這邊用圖片代替。

https://ithelp.ithome.com.tw/upload/images/20260802/20183331XxchgyMCXc.png

建立 server.NewAOFMiddleware()

// file: ./internal/server/middleware.go
package server

import (
	"context"
	"fmt"
	"olivine/internal/service"
	"olivine/pkg/resp"
)

func NewAOFMiddleware(aof service.AOF) Middleware {
	return func(next HandlerFunc) HandlerFunc {
		return func(ctx context.Context, cmd *resp.Command) (resp.Value, error) {
			// 這邊會讓 server.(Handler).ServeRESP 先執行完請求
			ret, err := next(ctx, cmd)
			if err != nil {
				return ret, err
			}

			// 沒有錯誤的話才會執行 aof.Write()
			if err := aof.Write(cmd); err != nil {
				return nil, fmt.Errorf("%w: failed to write AOF: %w", ErrServer, err)
			}

			return ret, nil
		}
	}
}

main.(*App) 中註冊 Middleware

// file: ./cmd/olivine/app.go
func NewApp() (*App, error) {
	aof, err := service.NewAOF("database.aof")
	if err != nil {
		return nil, err
	}

	return &App{
		srv: server.NewServer(server.NewHandler(cmd.NewCommands(repo.NewStorage()), server.NewAOFMiddleware(aof))),
	}, nil
}

上一篇
[Day 13] 資料持久化(上):AOF 的實現
下一篇
[Day 15] 資料持久化(下):從 AOF 恢復資料
系列文
從零開始打造 Redis:以 Go 建立 Production Ready 應用程式 15
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言