@Override
    public Result invoke(final Invocation invocation) throws RpcException {
        checkWhetherDestroyed();

        // binding attachments into invocation.
        //        Map<String, Object> contextAttachments = RpcContext.getClientAttachment().getObjectAttachments();
        //        if (contextAttachments != null && contextAttachments.size() != 0) {
        //            ((RpcInvocation) invocation).addObjectAttachmentsIfAbsent(contextAttachments);
        //        }

        InvocationProfilerUtils.enterDetailProfiler(invocation, () -> "Router route.");
        List<Invoker<T>> invokers = list(invocation);
        InvocationProfilerUtils.releaseDetailProfiler(invocation);

        checkInvokers(invokers, invocation);

        LoadBalance loadbalance = initLoadBalance(invokers, invocation);
        RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);

        InvocationProfilerUtils.enterDetailProfiler(
                invocation, () -> "Cluster " + this.getClass().getName() + " invoke.");
        try {
            return doInvoke(invocation, invokers, loadbalance);
        } finally {
            InvocationProfilerUtils.releaseDetailProfiler(invocation);
        }
    }
@Test
    void testTimeoutExceptionCode() {
        List<Invoker<DemoService>> invokers = new ArrayList<Invoker<DemoService>>();
        invokers.add(new Invoker<DemoService>() {

            @Override
            public Class<DemoService> getInterface() {
                return DemoService.class;
            }

            public URL getUrl() {
                return URL.valueOf("dubbo://" + NetUtils.getLocalHost() + ":20880/" + DemoService.class.getName());
            }

            @Override
            public boolean isAvailable() {
                return false;
            }

            @Override
            public Result invoke(Invocation invocation) throws RpcException {
                throw new RpcException(RpcException.TIMEOUT_EXCEPTION, "test timeout");
            }

            @Override
            public void destroy() {}
        });
        Directory<DemoService> directory = new StaticDirectory<DemoService>(invokers);
        FailoverClusterInvoker<DemoService> failoverClusterInvoker = new FailoverClusterInvoker<DemoService>(directory);
        RpcInvocation invocation =
                new RpcInvocation("sayHello", DemoService.class.getName(), "", new Class<?>[0], new Object[0]);
        try {
            failoverClusterInvoker.invoke(invocation);
            Assertions.fail();
        } catch (RpcException e) {
            Assertions.assertEquals(RpcException.TIMEOUT_EXCEPTION, e.getCode());
        }
        ForkingClusterInvoker<DemoService> forkingClusterInvoker = new ForkingClusterInvoker<DemoService>(directory);
        invocation = new RpcInvocation("sayHello", DemoService.class.getName(), "", new Class<?>[0], new Object[0]);
        try {
            forkingClusterInvoker.invoke(invocation);
            Assertions.fail();
        } catch (RpcException e) {
            Assertions.assertEquals(RpcException.TIMEOUT_EXCEPTION, e.getCode());
        }
        FailfastClusterInvoker<DemoService> failfastClusterInvoker = new FailfastClusterInvoker<DemoService>(directory);
        invocation = new RpcInvocation("sayHello", DemoService.class.getName(), "", new Class<?>[0], new Object[0]);
        try {
            failfastClusterInvoker.invoke(invocation);
            Assertions.fail();
        } catch (RpcException e) {
            Assertions.assertEquals(RpcException.TIMEOUT_EXCEPTION, e.getCode());
        }
    }