github.com/dubbogo/gost@v1.14.0/runtime/goroutine.go (about)

     1  /*
     2   * Licensed to the Apache Software Foundation (ASF) under one or more
     3   * contributor license agreements.  See the NOTICE file distributed with
     4   * this work for additional information regarding copyright ownership.
     5   * The ASF licenses this file to You under the Apache License, Version 2.0
     6   * (the "License"); you may not use this file except in compliance with
     7   * the License.  You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17  
    18  package gxruntime
    19  
    20  import (
    21  	"fmt"
    22  	"os"
    23  	"runtime/debug"
    24  	"sync"
    25  	"time"
    26  )
    27  
    28  // GoSafely wraps a `go func()` with recover()
    29  func GoSafely(wg *sync.WaitGroup, ignoreRecover bool, handler func(), catchFunc func(r interface{})) {
    30  	if wg != nil {
    31  		wg.Add(1)
    32  	}
    33  	go func() {
    34  		defer func() {
    35  			if r := recover(); r != nil {
    36  				if !ignoreRecover {
    37  					fmt.Fprintf(os.Stderr, "%s goroutine panic: %v\n%s\n",
    38  						time.Now(), r, string(debug.Stack()))
    39  				}
    40  				if catchFunc != nil {
    41  					if wg != nil {
    42  						wg.Add(1)
    43  					}
    44  					go func() {
    45  						defer func() {
    46  							if p := recover(); p != nil {
    47  								if !ignoreRecover {
    48  									fmt.Fprintf(os.Stderr, "recover goroutine panic:%v\n%s\n",
    49  										p, string(debug.Stack()))
    50  								}
    51  							}
    52  
    53  							if wg != nil {
    54  								wg.Done()
    55  							}
    56  						}()
    57  						catchFunc(r)
    58  					}()
    59  				}
    60  			}
    61  			if wg != nil {
    62  				wg.Done()
    63  			}
    64  		}()
    65  		handler()
    66  	}()
    67  }
    68  
    69  // GoUnterminated is used for which goroutine wanna long live as its process.
    70  // @period: sleep time duration after panic to defeat @handle panic so frequently. if it is not positive,
    71  //          the @handle will be invoked asap after panic.
    72  func GoUnterminated(handle func(), wg *sync.WaitGroup, ignoreRecover bool, period time.Duration) {
    73  	GoSafely(wg,
    74  		ignoreRecover,
    75  		handle,
    76  		func(r interface{}) {
    77  			if period > 0 {
    78  				time.Sleep(period)
    79  			}
    80  			GoUnterminated(handle, wg, ignoreRecover, period)
    81  		},
    82  	)
    83  }