Skip to content

Instantly share code, notes, and snippets.

@yusufsyaifudin
Created May 29, 2020 08:32
Show Gist options
  • Save yusufsyaifudin/1382ae3e9c6378784087682c6b7b9058 to your computer and use it in GitHub Desktop.
Save yusufsyaifudin/1382ae3e9c6378784087682c6b7b9058 to your computer and use it in GitHub Desktop.
package store_handler
import (
"encoding/json"
"fmt"
"github.com/hashicorp/raft"
"github.com/labstack/echo/v4"
"net/http"
"strings"
"time"
"ysf/raftsample/fsm"
)
// requestStore payload for storing new data in raft cluster
type requestStore struct {
Key string `json:"key"`
Value interface{} `json:"value"`
}
// Store handling save to raft cluster. Store will invoke raft.Apply to make this stored in all cluster
// with acknowledge from n quorum. Store must be done in raft leader, otherwise return error.
func (h handler) Store(eCtx echo.Context) error {
var form = requestStore{}
if err := eCtx.Bind(&form); err != nil {
return eCtx.JSON(http.StatusUnprocessableEntity, map[string]interface{}{
"error": fmt.Sprintf("error binding: %s", err.Error()),
})
}
form.Key = strings.TrimSpace(form.Key)
if form.Key == "" {
return eCtx.JSON(http.StatusUnprocessableEntity, map[string]interface{}{
"error": "key is empty",
})
}
if h.raft.State() != raft.Leader {
return eCtx.JSON(http.StatusUnprocessableEntity, map[string]interface{}{
"error": "not the leader",
})
}
payload := fsm.CommandPayload{
Operation: "SET",
Key: form.Key,
Value: form.Value,
}
data, err := json.Marshal(payload)
if err != nil {
return eCtx.JSON(http.StatusUnprocessableEntity, map[string]interface{}{
"error": fmt.Sprintf("error preparing saving data payload: %s", err.Error()),
})
}
applyFuture := h.raft.Apply(data, 500*time.Millisecond)
if err := applyFuture.Error(); err != nil {
return eCtx.JSON(http.StatusUnprocessableEntity, map[string]interface{}{
"error": fmt.Sprintf("error persisting data in raft cluster: %s", err.Error()),
})
}
_, ok := applyFuture.Response().(*fsm.ApplyResponse)
if !ok {
return eCtx.JSON(http.StatusUnprocessableEntity, map[string]interface{}{
"error": fmt.Sprintf("error response is not match apply response"),
})
}
return eCtx.JSON(http.StatusOK, map[string]interface{}{
"message": "success persisting data",
"data": form,
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment