Hobby project with microservices

Post Tag: techit

This post was inspired by awesome series of tutorials from Ewan Valentine. He built a small microservice oriented web application to select an appropriate ship for every consignment. Technology - Golang, PostgreSQL, MongoDB, gRPC, go-micro framework, React, Kubernetes. I followed through these tutorials. But made some additional “changes”. You can find them below.


General Overview:

Alt text


Notes:

httpMux.HandleFunc("/swagger/", func(w http.ResponseWriter, r *http.Request) {
  dir := "./proto/auth"
  if !strings.HasSuffix(r.URL.Path, ".swagger.json") {
    log.Printf("Swagger Not Found: %s", r.URL.Path)
    http.NotFound(w, r)
    return
  }
  log.Printf("Serving Swagger %s", r.URL.Path)
  p := strings.TrimPrefix(r.URL.Path, "/swagger/")
  p = path.Join(dir, p)
  fmt.Println(p)
  http.ServeFile(w, r, p)
})
// allowCORS allows Cross Origin Resoruce Sharing from any origin.
// Don't do this without consideration in production systems.
func allowCORS(h http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        if origin := r.Header.Get("Origin"); origin != "" {
            w.Header().Set("Access-Control-Allow-Origin", origin)
            if r.Method == "OPTIONS" && r.Header.Get("Access-Control-Request-Method") != "" {
                preflightHandler(w, r)
                return
            }
        }
        h.ServeHTTP(w, r)
    })
}

func preflightHandler(w http.ResponseWriter, r *http.Request) {
    headers := []string{"Content-Type", "Accept", "Authorization"}
    w.Header().Set("Access-Control-Allow-Headers", strings.Join(headers, ","))
    methods := []string{"GET", "HEAD", "POST", "PUT", "DELETE"}
    w.Header().Set("Access-Control-Allow-Methods", strings.Join(methods, ","))
    log.Printf("CORS preflight request for %s \n", r.URL.Path)
}
httpMux := http.NewServeMux()

httpMux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
  if err := db.DB().Ping(); err != nil {
    http.Error(w, http.StatusText(http.StatusServiceUnavailable), http.StatusServiceUnavailable)
    return
  }
  w.WriteHeader(http.StatusOK)
})
//Register in Consul
defer func() {
  cErr := consul.Agent().ServiceDeregister(serviceID)
  if cErr != nil {
    log.Println("Can't remove service from Consul ", cErr)
    return
  }
  log.Println("Remove from Consul ", serviceID)
}()

err = consul.Agent().ServiceRegister(&consulapi.AgentServiceRegistration{
  ID:      serviceID,
  Name:    "user-service",
  Port:    50054,
  Address: "host",
  Check: &consulapi.AgentServiceCheck{
    CheckID:  "health_check",
    Name:     "User-Service health status",
    Interval: "10s",
    GRPC:     "host:50054",
  },
})

if err != nil {
  log.Println("Couldn't add service to Consul, ", err)
}
log.Println("Add to Consul, ", serviceID)

//Get IP
ip, err := net.InterfaceAddrs()
if err != nil {
  log.Println("Couldn't get IP address")
}
for _, a := range ip {
  if ipnet, ok := a.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
    if ipnet.IP.To4() != nil {
      fmt.Println("MY IP: ", ipnet.IP)
    }
  }
}

//Get User-service from Consul
health, _, err := consul.Health().Service("user-service", "", true, nil)
if err != nil {
  log.Println("Cant get live services")
}

fmt.Println("HEALTH: ", len(health))
for _, item := range health {
  log.Println("Service: ", item.Service.ID, item.Service.Address, item.Service.Port)

}
// Check implements Consul health checking
func (srv *service) Check(ctx context.Context, in *pb.HealthCheckRequest) (*pb.HealthCheckResponse, error) {
    if err := srv.repo.ping(); err != nil {
        return &pb.HealthCheckResponse{
            Status: pb.HealthCheckResponse_NOT_SERVING,
        }, err
    }

    return &pb.HealthCheckResponse{Status: pb.HealthCheckResponse_SERVING}, nil
}
func (repo *ConsignmentRepository) Create(consignment *pb.Consignment) error {

    repo.collection().Insert(consignment)
    cons := []test{}
    repo.collection().Find(bson.M{"id": ""}).All(&cons)

    for i, v := range cons {
        fmt.Println(i, v.ID.Hex())
        consignment.Id = v.ID.Hex()
        repo.collection().Update(bson.M{"id": ""}, bson.M{"$set": bson.M{"id": v.ID.Hex()}})
    }

    return nil
}
comments powered by Disqus