fix: bump envoy submodule for doAfterVmCallActions drain-to-local (#4034) (#4080)

Signed-off-by: 澄潭 <zty98751@alibaba-inc.com>
This commit is contained in:
澄潭
2026-07-07 09:36:25 +08:00
committed by GitHub
parent d5f2b624fb
commit 4e4ca39b42
9 changed files with 480 additions and 2 deletions

View File

@@ -0,0 +1 @@
1.0.0-alpha

View File

@@ -0,0 +1,20 @@
module github.com/alibaba/higress/plugins/wasm-go/extensions/test-redis-inject-spin
go 1.24.1
toolchain go1.24.4
require (
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20251103120604-77e9cce339d2
github.com/higress-group/wasm-go v1.0.10-0.20260120033417-1c84f010156d
github.com/tidwall/gjson v1.18.0
github.com/tidwall/resp v0.1.1
google.golang.org/protobuf v1.36.6
)
require (
github.com/google/uuid v1.6.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/tidwall/sjson v1.2.5 // indirect
)

View File

@@ -0,0 +1,32 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20251103120604-77e9cce339d2 h1:NY33OrWCJJ+DFiLc+lsBY4Ywor2Ik61ssk6qkGF8Ypo=
github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20251103120604-77e9cce339d2/go.mod h1:tRI2LfMudSkKHhyv1uex3BWzcice2s/l8Ah8axporfA=
github.com/higress-group/wasm-go v1.0.10-0.20260120033417-1c84f010156d h1:LgYbzEBtg0+LEqoebQeMVgAB6H5SgqG+KN+gBhNfKbM=
github.com/higress-group/wasm-go v1.0.10-0.20260120033417-1c84f010156d/go.mod h1:uKVYICbRaxTlKqdm8E0dpjbysxM8uCPb9LV26hF3Km8=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/resp v0.1.1 h1:Ly20wkhqKTmDUPlyM1S7pWo5kk0tDu8OoC/vFArXmwE=
github.com/tidwall/resp v0.1.1/go.mod h1:3/FrruOBAxPTPtundW0VXgmsQ4ZBA0Aw714lVYgwFa0=
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -0,0 +1,119 @@
// Repro plugin for higress issue #4034: worker CPU spin in
// WasmBase::doAfterVmCallActions when a deferred async callback synchronously
// calls injectEncodedDataToFilterChain (nesting SaveRestoreContext) so that the
// after-vm-call action re-queues itself forever.
//
// Repro shape (dead-Redis only, self-contained — no external HTTP dependency):
// 1. In the response-header phase, pause the response.
// 2. Fire N Redis commands against an UNREACHABLE redis cluster.
// 3. Each failure callback (onRedisCallFailure) synchronously calls the
// inject_encoded_data_to_filter_chain foreign function. Because sibling
// failure callbacks are still queued as after-vm-call actions, the nested
// SaveRestoreContext leaves current_context_ != nullptr and the deferred
// action re-queues itself -> CPU spin on the pre-fix host.
//
// With the Layer A drain-to-local fix in place, the drain terminates over a
// snapshot and worker CPU stays bounded.
package main
import (
"github.com/higress-group/proxy-wasm-go-sdk/proxywasm"
"github.com/higress-group/proxy-wasm-go-sdk/proxywasm/types"
"github.com/higress-group/wasm-go/pkg/log"
pb "github.com/higress-group/wasm-go/pkg/protos"
"github.com/higress-group/wasm-go/pkg/wrapper"
"github.com/tidwall/gjson"
"github.com/tidwall/resp"
"google.golang.org/protobuf/proto"
)
func main() {}
type Config struct {
redisClient *wrapper.RedisClusterClient[wrapper.FQDNCluster]
redisKey string
injectBody string
injectCount int
}
func init() {
wrapper.SetCtx(
"test-redis-inject-spin",
wrapper.ParseConfig(parseConfig),
wrapper.ProcessResponseHeaders(onHttpResponseHeaders),
)
}
func parseConfig(json gjson.Result, config *Config) error {
serviceName := json.Get("service_name").String()
if serviceName == "" {
serviceName = "dead-redis.dead-redis.svc.cluster.local"
}
servicePort := json.Get("service_port").Int()
if servicePort == 0 {
servicePort = 6379
}
config.redisKey = json.Get("redis_key").String()
if config.redisKey == "" {
config.redisKey = "higress-4034-key"
}
config.injectBody = json.Get("inject_body").String()
if config.injectBody == "" {
config.injectBody = "injected-by-4034-repro\n"
}
config.injectCount = int(json.Get("inject_count").Int())
if config.injectCount == 0 {
config.injectCount = 16
}
config.redisClient = wrapper.NewRedisClusterClient(wrapper.FQDNCluster{
FQDN: serviceName,
Port: servicePort,
})
// Init never returns error for an unreachable host; commands' callbacks will
// fire with an error value, which is exactly the #4034 trigger path.
return config.redisClient.Init("", "", 1000)
}
func onHttpResponseHeaders(ctx wrapper.HttpContext, config Config) types.Action {
proxywasm.RemoveHttpResponseHeader("content-length")
ctx.DontReadResponseBody()
inject := func() {
d := &pb.InjectEncodedDataToFilterChainArguments{
Body: config.injectBody,
Endstream: true,
}
s, err := proto.Marshal(d)
if err != nil {
log.Errorf("marshal inject args failed: %+v", err)
return
}
if _, err := proxywasm.CallForeignFunction("inject_encoded_data_to_filter_chain_on_header", s); err != nil {
log.Errorf("call inject_encoded_data_to_filter_chain_on_header failed: %+v", err)
}
}
scheduled := 0
for i := 0; i < config.injectCount; i++ {
err := config.redisClient.Get(config.redisKey, func(response resp.Value) {
// Fires on redis-unreachable failure; synchronously inject to nest
// SaveRestoreContext while sibling callbacks are still queued.
if response.Error() != nil {
log.Debugf("redis get failed as expected: %v", response.Error())
}
inject()
})
if err != nil {
log.Errorf("redis Get dispatch failed: %+v", err)
continue
}
scheduled++
}
if scheduled == 0 {
// Nothing dispatched (e.g. cluster missing) — don't hang the response.
return types.ActionContinue
}
return types.ActionPause
}