Goroutine and panic have to tell the story

Source: Internet
Author: User

I previously know Golang also very superficial time, has been to goroutine thunderclap piercing, I believe many classmates and I, will think in Go code, Goroutine figure everywhere, in fact, is not so.

The two days involved a small project in the financial sector, which golang a small module in an old system from PHP code. Because the colleague in charge of the refactoring had only PHP experience, he sent me and another colleague to help. This morning the director came to see the progress, inadvertently looked at my code, immediately pointed out a serious bug, let me find a knowledge blind spot, I think it is worth sharing.

Process

Yesterday afternoon wrote an grpc interface, according to user_id query a table from the database user_config , get a city_ids field, is a city_id composition of the string, and then split processed after the city table to take the city data, the approximate process is similar to this:

func GetCities(userID int64) ([]*cityData, error) {    var (        strCityIDs string         CityIDs []string        ret []*cityData    )    strCityIDs, _ = userConfig.GetCityIDs(userID) //从user_config表查询city_id字段    CityIDs = strings.Split(strCityIDs, sep) //处理成id数组    err = city.Find(CityIDs, &ret) //从city表查出数据    return ret, err}

Speaking plainly is a has_many relationship. Because the city table will almost never change, early on the company, I think I can add a cache, so changed to:

func GetCities(userID int64) ([]*cityData, error) {    var (        strCityIDs string         CityIDs []string        ret []*cityData    )    strCityIDs, _ = userConfig.GetCityIDs(userID) //从user_config表查询city_id字段    err := cache.Get(prefix+strCityIDs, &ret) //先从缓存拿数据    if err == nil {        return ret, nil    }    CityIDs = strings.Split(strCityIDs, sep) //处理成id数组    err = city.Find(CityIDs, &ret) //从city表查出数据    if err == nil {        ok := cache.Set(prefix+strCityIDs, &ret, 12*time.Hour) //存入缓存        if !ok {            doNothing()        }    }    return ret, err}

After changing the "Turing" a move, think of oneself almost did not see in the company project saw the emergence of the go key words, oneself also basically did not in the production actually used goroutine , so cache.Set changed to go cache.Set . I think that the success of the cache does not affect the main process (even if it fails I do not do anything), so it can be given to the association to do, and so that goroutine the Lord can return faster.
Then the director came over.
Chatted two sentences, suddenly pointed to the code and said to me: "Here is wrong, can not use the co-process!" ”
Me: "Why?" ”
Director: "Because the panic inside the process will make the whole crash." ”
I was even more puzzled: "But I middleware Riga recover Ah, will catch panic." ”
middlewareCode:

func (*Interceptor) Method(ctx context.Context, srvInfo *core.SrvInfo, req interface{}, handler func(context.Context, interface{}) (interface{}, error)) (ret interface{}, err error) {    defer func() {        if p := recover(); p != nil {            err = fmt.Errorf("internal error: %v", p)        }    }()    ret, err = handler(ctx, req) //所有下层逻辑全部在这个函数里分发,所以我错误地认为任何panic都能在这里recover    return ret, err}

Director: "Goroutine occurs panic, only oneself can recover, other goroutine is not caught, this is common sense ah." ”
Me: "..."
Scared I did not dare to say anything, quickly go deleted the key words, and then the director left, immediately after the Internet to study a wave of goroutine, panic, recover relationship between, the following is the conclusion.

Conclusion

First, to be clear, it panic will stop the whole process, not just the current one, which means that the goroutine whole program is cool (and I now think that's the goroutine reason why there's no flooding in the code, and the other reason is, I think that in the case of the cpu nuclear all running up, more goroutine can also be concurrent and not parallel).
Second, panic is the orderly, controllable stop program, not bam down, so we can also use recover remediation.
Then, it recover can only defer take effect in the inside, if not in the defer call, will return directly nil .
Finally, it is important to note that goroutine when it happens, it panic only calls itself defer , so even if the Lord goroutine writes recover logic, it cannot be saved in goroutine the other panic .
So, the previous writing go cache.Set is very dangerous, because it cache did not do anything recover , once it appears panic , will affect the entire system.
Let's say I'm going to put this in the go keyword implementation (obviously I'm not such a person), the code can be changed to:

  go func () {defer func () {if r: = Recover (); r! = nil {fmt. Println ("Don t worry, I can take care of Myself")}} () cache. Set (Prefix+strcityids, &ret, 12*time. Hour)//cache} ()  
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.