@Override
    public void subscribe(URL url, NotifyListener listener) {
        super.subscribe(url, listener);
        removeFailedSubscribed(url, listener);
        try {
            // Sending a subscription request to the server side
            doSubscribe(url, listener);
        } catch (Exception e) {
            Throwable t = e;

            List<URL> urls = getCacheUrls(url);
            if (CollectionUtils.isNotEmpty(urls)) {
                notify(url, listener, urls);
                logger.error(
                        REGISTRY_FAILED_NOTIFY_EVENT,
                        "",
                        "",
                        "Failed to subscribe " + url + ", Using cached list: " + urls + " from cache file: "
                                + getCacheFile().getName() + ", cause: " + t.getMessage(),
                        t);
            } else {
                // If the startup detection is opened, the Exception is thrown directly.
                boolean check =
                        getUrl().getParameter(Constants.CHECK_KEY, true) && url.getParameter(Constants.CHECK_KEY, true);
                boolean skipFailback = t instanceof SkipFailbackWrapperException;
                if (check || skipFailback) {
                    if (skipFailback) {
                        t = t.getCause();
                    }
                    throw new IllegalStateException("Failed to subscribe " + url + ", cause: " + t.getMessage(), t);
                } else {
                    logger.error(
                            REGISTRY_FAILED_NOTIFY_EVENT,
                            "",
                            "",
                            "Failed to subscribe " + url + ", waiting for retry, cause: " + t.getMessage(),
                            t);
                }
            }

            // Record a failed registration request to a failed list, retry regularly
            addFailedSubscribed(url, listener);
        }
    }
@Test
    void testDoRetrySubscribe() throws Exception {

        final AtomicReference<Boolean> notified = new AtomicReference<Boolean>(false);
        final CountDownLatch latch = new CountDownLatch(
                1); // All of them are called 4 times. A successful attempt to lose 1. subscribe will not be done

        NotifyListener listener = urls -> notified.set(Boolean.TRUE);
        registry = new MockRegistry(registryUrl, serviceUrl, latch);
        registry.setBad(true);
        registry.subscribe(
                serviceUrl.setProtocol(CONSUMER_PROTOCOL).addParameters(CollectionUtils.toStringMap("check", "false")),
                listener);

        // Failure can not be called to listener.
        assertEquals(false, notified.get());
        assertEquals(1, latch.getCount());

        registry.setBad(false);

        for (int i = 0; i < tryTimes; i++) {
            System.out.println("failback registry retry ,times:" + i);
            if (latch.getCount() == 0) break;
            Thread.sleep(sleepTime);
        }
        assertEquals(0, latch.getCount());
        // The failed subscribe corresponding key will be cleared when unsubscribing
        assertEquals(true, notified.get());
    }