聊聊快取布林值踩到的坑

linyb極客之路發表於2022-04-19

前言

有這麼一個業務場景:部門A服務要使用部門B服務的業務資料,部門A服務使用部門B服務的業務資料前置條件是B部門必須要給A授權。B部門的授權和業務資料分屬為不同服務。其請求流程如下


因為A的鑑權資訊的請求值是固定的,因此鑑權結果大概率也是固定值。當時B部門的業務服務開發同事,為了提高效率。就加了快取,即B的業務服務會將A的鑑權結果快取起來。當時寫法形如下

 private final LoadingCache<String,Boolean> checkSvcCache = Caffeine
            .newBuilder().maximumSize(Constants.MAX_SIZE)
            .expireAfterWrite(Conastants.EXPIRE, TimeUnit.DAYS)
            .build(key -> loadCache(key));

    @Nullable
    private Boolean loadCache(@NonNull String key) {
        if(key.contains(Constant.UNDER_LINE)){
            try {
                String[] arr = key.split(Constant.UNDER_LINE);
                Integer ak = Integer.parseInt(arr[0]);
                String sk = arr[1];
                RPCResult<Boolean> result = authService.checkSvc(ak, sk);
                if(result.getSuccess()){
                    Boolean data = result.getData();
                    return data;
                }
                return false;
            } catch (Exception e) {
                log.error("{}",e);
            }
        }
        return false;
    }

思考

大家看下上述程式碼塊的寫法有沒有問題?

粗看貌似沒啥問題,但實際是有點小問題的。當進行遠端呼叫時,如果出現異常,此時布林值會返回false。這樣就可能把正確的結果給掩蓋了,比如明明都按約定的 ak,sk傳值了,結果返回鑑權失敗。

修復

那要如何修復?扯一點哲學東西,這個世界不是非黑即白,其實可能還存在灰色地帶。布林值在java的世界中,也不是就只有true或者false,當布林值為包裝類時,他還有一種狀態是null。因此可以修改為

@Nullable
    private Boolean loadCache(@NonNull String key) {
        if(key.contains(Constant.UNDER_LINE)){
            try {
                String[] arr = key.split(Constant.UNDER_LINE);
                Integer ak = Integer.parseInt(arr[0]);
                String sk = arr[1];
                RPCResult<Boolean> result = authService.checkSvc(ak, sk);
                if(result.getSuccess()){
                    Boolean data = result.getData();
                    return data;
                }
                return false;
            } catch (Exception e) {
                log.error("{}",e);
            }
        }
        return null;
    }

但這樣改就沒問題了嗎,其實還是有問題,因為null值也不是正確結果。但我們可以利用null來額外做一些異常兜底。比如出現null時,就是有問題了,我們可以對A進行友好的提示,而非返回鑑權失敗,也便於提前暴露問題,而下次請求進來時,快取會因為值為null,再次觸發遠端呼叫

總結

異常流程思考很重要。。。

相關文章