cmd/go-runner/plugins/limit_req.go (47 lines of code) (raw):

// Licensed to the Apache Software Foundation (ASF) under one or more // contributor license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright ownership. // The ASF licenses this file to You under the Apache License, Version 2.0 // (the "License"); you may not use this file except in compliance with // the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package plugins import ( "encoding/json" "net/http" "time" "golang.org/x/time/rate" pkgHTTP "github.com/apache/apisix-go-plugin-runner/pkg/http" "github.com/apache/apisix-go-plugin-runner/pkg/log" "github.com/apache/apisix-go-plugin-runner/pkg/plugin" ) func init() { err := plugin.RegisterPlugin(&LimitReq{}) if err != nil { log.Fatalf("failed to register plugin limit-req: %s", err) } } // LimitReq is a demo for a real world plugin type LimitReq struct { // Embed the default plugin here, // so that we don't need to reimplement all the methods. plugin.DefaultPlugin } type LimitReqConf struct { Burst int `json:"burst"` Rate float64 `json:"rate"` limiter *rate.Limiter } func (p *LimitReq) Name() string { return "limit-req" } // ParseConf is called when the configuration is changed. And its output is unique per route. func (p *LimitReq) ParseConf(in []byte) (interface{}, error) { conf := LimitReqConf{} err := json.Unmarshal(in, &conf) if err != nil { return nil, err } limiter := rate.NewLimiter(rate.Limit(conf.Rate), conf.Burst) // the conf can be used to store route scope data conf.limiter = limiter return conf, nil } // RequestFilter is called when a request hits the route func (p *LimitReq) RequestFilter(conf interface{}, w http.ResponseWriter, r pkgHTTP.Request) { li := conf.(LimitReqConf).limiter rs := li.Reserve() if !rs.OK() { // limit rate exceeded log.Infof("limit req rate exceeded") // stop filters with this response w.WriteHeader(http.StatusServiceUnavailable) return } time.Sleep(rs.Delay()) }