Skip to content
Snippets Groups Projects
Commit dab49ec5 authored by pantianying's avatar pantianying
Browse files

Merge branch 'develop' of https://github.com/apache/dubbo-go into apache-develop

parents 23a7df9f 3122a2b2
No related branches found
No related tags found
No related merge requests found
Showing
with 607 additions and 7 deletions
::
:: 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.
set zkJar=zookeeper-3.4.9-fatjar.jar
md remoting\zookeeper\zookeeper-4unittest\contrib\fatjar config_center\zookeeper\zookeeper-4unittest\contrib\fatjar registry\zookeeper\zookeeper-4unittest\contrib\fatjar
curl -L https://github.com/dubbogo/resources/raw/master/zookeeper-4unitest/contrib/fatjar/%zkJar% -o remoting/zookeeper/zookeeper-4unittest/contrib/fatjar/%zkJar%
......
#
# 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.
mkdir -p remoting/zookeeper/zookeeper-4unittest/contrib/fatjar config_center/zookeeper/zookeeper-4unittest/contrib/fatjar registry/zookeeper/zookeeper-4unittest/contrib/fatjar
wget -P "remoting/zookeeper/zookeeper-4unittest/contrib/fatjar" https://github.com/dubbogo/resources/raw/master/zookeeper-4unitest/contrib/fatjar/zookeeper-3.4.9-fatjar.jar
cp remoting/zookeeper/zookeeper-4unittest/contrib/fatjar/zookeeper-3.4.9-fatjar.jar config_center/zookeeper/zookeeper-4unittest/contrib/fatjar/
......
......@@ -46,8 +46,8 @@ const (
const (
DEFAULT_KEY = "default"
PREFIX_DEFAULT_KEY = "default."
DEFAULT_SERVICE_FILTERS = "echo,token,accesslog,tps,execute"
DEFAULT_REFERENCE_FILTERS = ""
DEFAULT_SERVICE_FILTERS = "echo,token,accesslog,tps,execute,pshutdown"
DEFAULT_REFERENCE_FILTERS = "cshutdown"
GENERIC_REFERENCE_FILTERS = "generic"
GENERIC = "$invoke"
ECHO = "$echo"
......
......@@ -71,6 +71,8 @@ const (
EXECUTE_LIMIT_KEY = "execute.limit"
DEFAULT_EXECUTE_LIMIT = "-1"
EXECUTE_REJECTED_EXECUTION_HANDLER_KEY = "execute.limit.rejected.handler"
PROVIDER_SHUTDOWN_FILTER = "pshutdown"
CONSUMER_SHUTDOWN_FILTER = "cshutdown"
)
const (
......@@ -115,6 +117,7 @@ const (
ProtocolConfigPrefix = "dubbo.protocols."
ProviderConfigPrefix = "dubbo.provider."
ConsumerConfigPrefix = "dubbo.consumer."
ShutdownConfigPrefix = "dubbo.shutdown."
)
const (
......
/*
* 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 extension
import (
"container/list"
)
var (
customShutdownCallbacks = list.New()
)
/**
* you should not make any assumption about the order.
* For example, if you have more than one callbacks, and you wish the order is:
* callback1()
* callback2()
* ...
* callbackN()
* Then you should put then together:
* func callback() {
* callback1()
* callback2()
* ...
* callbackN()
* }
* I think the order of custom callbacks should be decided by the users.
* Even though I can design a mechanism to support the ordered custom callbacks,
* the benefit of that mechanism is low.
* And it may introduce much complication for another users.
*/
func AddCustomShutdownCallback(callback func()) {
customShutdownCallbacks.PushBack(callback)
}
func GetAllCustomShutdownCallbacks() *list.List {
return customShutdownCallbacks
}
......@@ -40,6 +40,7 @@ func Test_refresh(t *testing.T) {
mockMap["dubbo.com.MockService.MockService.GetUser.retries"] = "10"
mockMap["dubbo.consumer.check"] = "false"
mockMap["dubbo.application.name"] = "dubbo"
mockMap["dubbo.shutdown.timeout"] = "12s"
config.GetEnvInstance().UpdateExternalConfigMap(mockMap)
......@@ -114,6 +115,13 @@ func Test_refresh(t *testing.T) {
},
},
},
ShutdownConfig: &ShutdownConfig{
Timeout: "12s",
StepTimeout: "2s",
RejectRequestHandler: "mock",
RejectRequest: false,
RequestsFinished: false,
},
}
c.SetFatherConfig(father)
......
......@@ -149,6 +149,8 @@ func Load() {
}
}
}
// init the shutdown callback
GracefulShutdownInit()
}
// get rpc service for consumer
......
......@@ -52,11 +52,12 @@ type ConsumerConfig struct {
ProxyFactory string `yaml:"proxy_factory" default:"default" json:"proxy_factory,omitempty" property:"proxy_factory"`
Check *bool `yaml:"check" json:"check,omitempty" property:"check"`
Registry *RegistryConfig `yaml:"registry" json:"registry,omitempty" property:"registry"`
Registries map[string]*RegistryConfig `yaml:"registries" json:"registries,omitempty" property:"registries"`
References map[string]*ReferenceConfig `yaml:"references" json:"references,omitempty" property:"references"`
ProtocolConf interface{} `yaml:"protocol_conf" json:"protocol_conf,omitempty" property:"protocol_conf"`
FilterConf interface{} `yaml:"filter_conf" json:"filter_conf,omitempty" property:"filter_conf" `
Registry *RegistryConfig `yaml:"registry" json:"registry,omitempty" property:"registry"`
Registries map[string]*RegistryConfig `yaml:"registries" json:"registries,omitempty" property:"registries"`
References map[string]*ReferenceConfig `yaml:"references" json:"references,omitempty" property:"references"`
ProtocolConf interface{} `yaml:"protocol_conf" json:"protocol_conf,omitempty" property:"protocol_conf"`
FilterConf interface{} `yaml:"filter_conf" json:"filter_conf,omitempty" property:"filter_conf" `
ShutdownConfig *ShutdownConfig `yaml:"shutdown_conf" json:"shutdown_conf,omitempty" property:"shutdown_conf" `
}
func (c *ConsumerConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
......
/*
* 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 config
import (
"os"
"os/signal"
"runtime/debug"
"syscall"
"time"
)
import (
"github.com/dubbogo/gost/container/gxset"
)
import (
"github.com/apache/dubbo-go/common/constant"
"github.com/apache/dubbo-go/common/extension"
"github.com/apache/dubbo-go/common/logger"
)
/*
* The key point is that find out the signals to handle.
* The most important documentation is https://golang.org/pkg/os/signal/
* From this documentation, we can know that:
* 1. The signals SIGKILL and SIGSTOP may not be caught by signal package;
* 2. SIGHUP, SIGINT, or SIGTERM signal causes the program to exit
* 3. SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGSTKFLT, SIGEMT, or SIGSYS signal causes the program to exit with a stack dump
* 4. The invocation of Notify(signal...) will disable the default behavior of those signals.
*
* So the signals SIGKILL, SIGSTOP, SIGHUP, SIGINT, SIGTERM, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGSTKFLT, SIGEMT, SIGSYS
* should be processed.
* syscall.SIGEMT cannot be found in CI
* It's seems that the Unix/Linux does not have the signal SIGSTKFLT. https://github.com/golang/go/issues/33381
* So this signal will be ignored.
*
*/
func GracefulShutdownInit() {
signals := make(chan os.Signal, 1)
signal.Notify(signals, os.Interrupt, os.Kill, syscall.SIGKILL, syscall.SIGSTOP,
syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGILL, syscall.SIGTRAP,
syscall.SIGABRT, syscall.SIGSYS,
)
go func() {
select {
case sig := <-signals:
logger.Infof("get signal %s, application will shutdown.", sig)
// gracefulShutdownOnce.Do(func() {
BeforeShutdown()
switch sig {
// those signals' original behavior is exit with dump ths stack, so we try to keep the behavior
case syscall.SIGQUIT, syscall.SIGILL, syscall.SIGTRAP,
syscall.SIGABRT, syscall.SIGSYS:
debug.WriteHeapDump(os.Stdout.Fd())
default:
time.AfterFunc(totalTimeout(), func() {
logger.Warn("Shutdown gracefully timeout, application will shutdown immediately. ")
os.Exit(0)
})
}
os.Exit(0)
}
}()
}
func BeforeShutdown() {
destroyAllRegistries()
// waiting for a short time so that the clients have enough time to get the notification that server shutdowns
// The value of configuration depends on how long the clients will get notification.
waitAndAcceptNewRequests()
// reject the new request, but keeping waiting for accepting requests
waitForReceivingRequests()
// we fetch the protocols from Consumer.References. Consumer.ProtocolConfig doesn't contains all protocol, like jsonrpc
consumerProtocols := getConsumerProtocols()
// If this application is not the provider, it will do nothing
destroyProviderProtocols(consumerProtocols)
// reject sending the new request, and waiting for response of sending requests
waitForSendingRequests()
// If this application is not the consumer, it will do nothing
destroyConsumerProtocols(consumerProtocols)
logger.Info("Graceful shutdown --- Execute the custom callbacks.")
customCallbacks := extension.GetAllCustomShutdownCallbacks()
for callback := customCallbacks.Front(); callback != nil; callback = callback.Next() {
callback.Value.(func())()
}
}
func destroyAllRegistries() {
logger.Info("Graceful shutdown --- Destroy all registries. ")
registryProtocol := extension.GetProtocol(constant.REGISTRY_KEY)
registryProtocol.Destroy()
}
func destroyConsumerProtocols(consumerProtocols *gxset.HashSet) {
logger.Info("Graceful shutdown --- Destroy consumer's protocols. ")
for name := range consumerProtocols.Items {
extension.GetProtocol(name.(string)).Destroy()
}
}
/**
* destroy the provider's protocol.
* if the protocol is consumer's protocol too, we will keep it.
*/
func destroyProviderProtocols(consumerProtocols *gxset.HashSet) {
logger.Info("Graceful shutdown --- Destroy provider's protocols. ")
if providerConfig == nil || providerConfig.Protocols == nil {
return
}
for _, protocol := range providerConfig.Protocols {
// the protocol is the consumer's protocol too, we can not destroy it.
if consumerProtocols.Contains(protocol.Name) {
continue
}
extension.GetProtocol(protocol.Name).Destroy()
}
}
func waitAndAcceptNewRequests() {
logger.Info("Graceful shutdown --- Keep waiting and accept new requests for a short time. ")
if providerConfig == nil || providerConfig.ShutdownConfig == nil {
return
}
timeout := providerConfig.ShutdownConfig.GetStepTimeout()
// ignore this step
if timeout < 0 {
return
}
time.Sleep(timeout)
}
// for provider. It will wait for processing receiving requests
func waitForReceivingRequests() {
logger.Info("Graceful shutdown --- Keep waiting until accepting requests finish or timeout. ")
if providerConfig == nil || providerConfig.ShutdownConfig == nil {
// ignore this step
return
}
waitingProcessedTimeout(providerConfig.ShutdownConfig)
}
// for consumer. It will wait for the response of sending requests
func waitForSendingRequests() {
logger.Info("Graceful shutdown --- Keep waiting until sending requests getting response or timeout ")
if consumerConfig == nil || consumerConfig.ShutdownConfig == nil {
// ignore this step
return
}
waitingProcessedTimeout(consumerConfig.ShutdownConfig)
}
func waitingProcessedTimeout(shutdownConfig *ShutdownConfig) {
timeout := shutdownConfig.GetStepTimeout()
if timeout <= 0 {
return
}
start := time.Now()
for time.Now().After(start.Add(timeout)) && !shutdownConfig.RequestsFinished {
// sleep 10 ms and then we check it again
time.Sleep(10 * time.Millisecond)
}
}
func totalTimeout() time.Duration {
var providerShutdown time.Duration
if providerConfig != nil && providerConfig.ShutdownConfig != nil {
providerShutdown = providerConfig.ShutdownConfig.GetTimeout()
}
var consumerShutdown time.Duration
if consumerConfig != nil && consumerConfig.ShutdownConfig != nil {
consumerShutdown = consumerConfig.ShutdownConfig.GetTimeout()
}
var timeout = providerShutdown
if consumerShutdown > providerShutdown {
timeout = consumerShutdown
}
return timeout
}
/*
* we can not get the protocols from consumerConfig because some protocol don't have configuration, like jsonrpc.
*/
func getConsumerProtocols() *gxset.HashSet {
result := gxset.NewSet()
if consumerConfig == nil || consumerConfig.References == nil {
return result
}
for _, reference := range consumerConfig.References {
result.Add(reference.Protocol)
}
return result
}
/*
* 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 config
import (
"time"
)
import (
"github.com/apache/dubbo-go/common/constant"
"github.com/apache/dubbo-go/common/logger"
)
const (
defaultTimeout = 60 * time.Second
defaultStepTimeout = 10 * time.Second
)
type ShutdownConfig struct {
/*
* Total timeout. Even though we don't release all resources,
* the application will shutdown if the costing time is over this configuration. The unit is ms.
* default value is 60 * 1000 ms = 1 minutes
* In general, it should be bigger than 3 * StepTimeout.
*/
Timeout string `default:"60s" yaml:"timeout" json:"timeout,omitempty" property:"timeout"`
/*
* the timeout on each step. You should evaluate the response time of request
* and the time that client noticed that server shutdown.
* For example, if your client will received the notification within 10s when you start to close server,
* and the 99.9% requests will return response in 2s, so the StepTimeout will be bigger than(10+2) * 1000ms,
* maybe (10 + 2*3) * 1000ms is a good choice.
*/
StepTimeout string `default:"10s" yaml:"step_timeout" json:"step.timeout,omitempty" property:"step.timeout"`
// when we try to shutdown the application, we will reject the new requests. In most cases, you don't need to configure this.
RejectRequestHandler string `yaml:"reject_handler" json:"reject_handler,omitempty" property:"reject_handler"`
// true -> new request will be rejected.
RejectRequest bool
// true -> all requests had been processed. In provider side it means that all requests are returned response to clients
// In consumer side, it means that all requests getting response from servers
RequestsFinished bool
}
func (config *ShutdownConfig) Prefix() string {
return constant.ShutdownConfigPrefix
}
func (config *ShutdownConfig) GetTimeout() time.Duration {
result, err := time.ParseDuration(config.Timeout)
if err != nil {
logger.Errorf("The Timeout configuration is invalid: %s, and we will use the default value: %s, err: %v",
config.Timeout, defaultTimeout.String(), err)
return defaultTimeout
}
return result
}
func (config *ShutdownConfig) GetStepTimeout() time.Duration {
result, err := time.ParseDuration(config.StepTimeout)
if err != nil {
logger.Errorf("The StepTimeout configuration is invalid: %s, and we will use the default value: %s, err: %v",
config.StepTimeout, defaultStepTimeout.String(), err)
return defaultStepTimeout
}
return result
}
/*
* 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 config
import (
"testing"
"time"
)
import (
"github.com/stretchr/testify/assert"
)
func TestShutdownConfig_GetTimeout(t *testing.T) {
config := ShutdownConfig{}
assert.False(t, config.RejectRequest)
assert.False(t, config.RequestsFinished)
config = ShutdownConfig{
Timeout: "12x",
StepTimeout: "34a",
}
assert.Equal(t, 60*time.Second, config.GetTimeout())
assert.Equal(t, 10*time.Second, config.GetStepTimeout())
config = ShutdownConfig{
Timeout: "34ms",
StepTimeout: "79ms",
}
assert.Equal(t, 34*time.Millisecond, config.GetTimeout())
assert.Equal(t, 79*time.Millisecond, config.GetStepTimeout())
}
/*
* 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 config
import (
"testing"
)
import (
"github.com/apache/dubbo-go/common/constant"
"github.com/apache/dubbo-go/common/extension"
"github.com/apache/dubbo-go/protocol"
)
func TestGracefulShutdownInit(t *testing.T) {
GracefulShutdownInit()
}
func TestBeforeShutdown(t *testing.T) {
extension.SetProtocol("registry", func() protocol.Protocol {
return &mockRegistryProtocol{}
})
extension.SetProtocol(constant.DUBBO, func() protocol.Protocol {
return &mockRegistryProtocol{}
})
extension.SetProtocol("mock", func() protocol.Protocol {
return &mockRegistryProtocol{}
})
// protocolConfigs := make(map[interface{}]interface{}, 16)
consumerReferences := map[string]*ReferenceConfig{}
consumerReferences[constant.DUBBO] = &ReferenceConfig{
Protocol: constant.DUBBO,
}
// without configuration
BeforeShutdown()
consumerConfig = &ConsumerConfig{
References: consumerReferences,
ShutdownConfig: &ShutdownConfig{
Timeout: "1",
StepTimeout: "1s",
}}
providerProtocols := map[string]*ProtocolConfig{}
providerProtocols[constant.DUBBO] = &ProtocolConfig{
Name: constant.DUBBO,
}
providerProtocols["mock"] = &ProtocolConfig{
Name: "mock",
}
providerConfig = &ProviderConfig{
ShutdownConfig: &ShutdownConfig{
Timeout: "1",
StepTimeout: "1s",
},
Protocols: providerProtocols,
}
// test destroy protocol
BeforeShutdown()
providerConfig = &ProviderConfig{
ShutdownConfig: &ShutdownConfig{
Timeout: "1",
StepTimeout: "-1s",
},
Protocols: providerProtocols,
}
consumerConfig = &ConsumerConfig{
References: consumerReferences,
ShutdownConfig: &ShutdownConfig{
Timeout: "1",
StepTimeout: "-1s",
},
}
// test ignore steps
BeforeShutdown()
}
......@@ -49,6 +49,7 @@ type ProviderConfig struct {
Protocols map[string]*ProtocolConfig `yaml:"protocols" json:"protocols,omitempty" property:"protocols"`
ProtocolConf interface{} `yaml:"protocol_conf" json:"protocol_conf,omitempty" property:"protocol_conf" `
FilterConf interface{} `yaml:"filter_conf" json:"filter_conf,omitempty" property:"filter_conf" `
ShutdownConfig *ShutdownConfig `yaml:"shutdown_conf" json:"shutdown_conf,omitempty" property:"shutdown_conf" `
}
func (c *ProviderConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
......@@ -106,6 +107,7 @@ func ProviderInit(confProFile string) error {
}
logger.Debugf("provider config{%#v}\n", providerConfig)
return nil
}
......
/*
* 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 config
import (
......
......@@ -49,6 +49,10 @@ references:
"soa.com.ikurento.user.UserProvider"
"forks": 5
shutdown_conf:
timeout: 60s
step_timeout: 10s
protocol_conf:
dubbo:
reconnect_interval: 0
......
......@@ -17,6 +17,10 @@ references:
- name: "GetUser"
retries: "3"
shutdown_conf:
timeout: 60s
step_timeout: 10s
protocol_conf:
dubbo:
reconnect_interval: 0
......
......@@ -48,6 +48,10 @@ references:
"soa.com.ikurento.user.UserProvider"
"forks": 5
shutdown_conf:
timeout: 60s
step_timeout: 10s
protocol_conf:
dubbo:
reconnect_interval: 0
......
......@@ -71,6 +71,10 @@ protocols:
# ip: "127.0.0.1"
# port: 20001
shutdown_conf:
timeout: 60s
step_timeout: 10s
protocol_conf:
dubbo:
session_number: 700
......
......@@ -51,6 +51,10 @@ protocols:
# ip: "127.0.0.1"
# port: 20001
shutdown_conf:
timeout: 60s
step_timeout: 10s
protocol_conf:
dubbo:
session_number: 700
......
dubbogo.png

56.7 KiB

0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment