github.com/aacfactory/fns@v1.2.86-0.20240310083819-80d667fc0a17/runtime/health.go (about)

     1  /*
     2   * Copyright 2023 Wang Min Xiang
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   * 	http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   *
    16   */
    17  
    18  package runtime
    19  
    20  import (
    21  	"bytes"
    22  	"github.com/aacfactory/avro"
    23  	"github.com/aacfactory/fns/commons/bytex"
    24  	"github.com/aacfactory/fns/context"
    25  	"github.com/aacfactory/fns/transports"
    26  	"github.com/aacfactory/json"
    27  	"time"
    28  )
    29  
    30  var (
    31  	healthPath = bytex.FromString("/health")
    32  )
    33  
    34  func CheckHealth(ctx context.Context, client transports.Client) (ok bool) {
    35  	status, header, body, _ := client.Do(ctx, transports.MethodGet, healthPath, nil, nil)
    36  	if status != 200 {
    37  		return
    38  	}
    39  	health := Health{}
    40  	if bytes.Equal(header.Get(transports.ContentTypeHeaderName), transports.ContentTypeAvroHeaderValue) {
    41  		decodeErr := avro.Unmarshal(body, &health)
    42  		if decodeErr != nil {
    43  			return
    44  		}
    45  	} else {
    46  		decodeErr := json.Unmarshal(body, &health)
    47  		if decodeErr != nil {
    48  			return
    49  		}
    50  	}
    51  	ok = health.Running
    52  	return
    53  }
    54  
    55  func HealthHandler() transports.MuxHandler {
    56  	return &healthHandler{
    57  		launch: time.Now(),
    58  	}
    59  }
    60  
    61  type healthHandler struct {
    62  	launch time.Time
    63  }
    64  
    65  func (handler *healthHandler) Name() string {
    66  	return "health"
    67  }
    68  
    69  func (handler *healthHandler) Construct(_ transports.MuxHandlerOptions) error {
    70  	return nil
    71  }
    72  
    73  func (handler *healthHandler) Match(_ context.Context, method []byte, path []byte, _ transports.Header) bool {
    74  	ok := bytes.Equal(method, transports.MethodGet) && bytes.Equal(path, healthPath)
    75  	return ok
    76  }
    77  
    78  func (handler *healthHandler) Handle(w transports.ResponseWriter, r transports.Request) {
    79  	rt := Load(r)
    80  	running, serving := rt.Running()
    81  	w.Succeed(Health{
    82  		Id:      bytex.ToString(rt.AppId()),
    83  		Name:    rt.AppName(),
    84  		Version: rt.AppVersion().String(),
    85  		Running: running,
    86  		Serving: serving,
    87  		Launch:  handler.launch,
    88  		Now:     time.Now(),
    89  	})
    90  	return
    91  }
    92  
    93  type Health struct {
    94  	Id      string    `json:"id" avro:"id"`
    95  	Name    string    `json:"name" avro:"name"`
    96  	Version string    `json:"version" avro:"version"`
    97  	Running bool      `json:"running" avro:"running"`
    98  	Serving bool      `json:"serving" avro:"serving"`
    99  	Launch  time.Time `json:"launch" avro:"launch"`
   100  	Now     time.Time `json:"now" avro:"now"`
   101  }