Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Seata Client should allow dynamic monitoring of changes in service.default.grouplist #7039

Closed
linghengqian opened this issue Dec 1, 2024 · 5 comments

Comments

@linghengqian
Copy link
Member

linghengqian commented Dec 1, 2024

Why you need it?

Is your feature request related to a problem? Please describe in details

  • When writing the unit test of Seata Client inside Apache ShardingSphere, I dynamically set the service.default.grouplist of Seata Client by setting the System Properties.
  • But there is a problem, Seata Client currently only listens to System Properties once. I created a minimal reproducible unit test at https://github.com/linghengqian/seata-client-re-create-test . Verified unit test under Ubuntu 22.04.4 LTS with SDKMAN! and Docker CE.
sdk install java 23-open

git clone [email protected]:linghengqian/seata-client-re-create-test.git
cd ./seata-client-re-create-test/
sdk use java 23-open
./mvnw -T 1C clean test

The core logic is as follows:

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.apache.seata.core.rpc.netty.RmNettyRemotingClient;
import org.apache.seata.core.rpc.netty.TmNettyRemotingClient;
import org.apache.seata.rm.RMClient;
import org.apache.seata.rm.datasource.DataSourceProxy;
import org.apache.seata.tm.TMClient;
import org.awaitility.Awaitility;
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.wait.strategy.Wait;
import java.time.Duration;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
@SuppressWarnings("resource")
public class SimpleTest {
    @Test
    void test() {
        assertThat(System.getProperty("service.default.grouplist"), is(nullValue()));
        assertDoesNotThrow(() -> extracted("jdbc:tc:postgresql:17.1-bookworm://test/demo_ds_0?TC_INITSCRIPT=init.sql"));
        assertDoesNotThrow(() -> extracted("jdbc:tc:postgresql:17.1-bookworm://test/demo_ds_1?TC_INITSCRIPT=init.sql"));
    }
    private static void extracted(final String jdbcUrl) {
        try (GenericContainer<?> seataContainer = new GenericContainer<>("apache/seata-server:2.1.0")
                .withExposedPorts(7091, 8091)
                .waitingFor(Wait.forHttp("/health").forPort(7091).forStatusCode(200).forResponsePredicate("ok"::equals))
        ) {
            seataContainer.start();
            System.setProperty("service.default.grouplist", "127.0.0.1:" + seataContainer.getMappedPort(8091));
            TMClient.init("test-first", "default_tx_group");
            RMClient.init("test-first", "default_tx_group");
            HikariConfig config = new HikariConfig();
            config.setDriverClassName("org.testcontainers.jdbc.ContainerDatabaseDriver");
            config.setJdbcUrl(jdbcUrl);
            try (HikariDataSource hikariDataSource = new HikariDataSource(config)) {
                DataSourceProxy seataDataSource = new DataSourceProxy(hikariDataSource);
                Awaitility.await().atMost(Duration.ofSeconds(15L)).ignoreExceptions().until(() -> {
                    seataDataSource.getConnection().close();
                    return true;
                });
            }
            RmNettyRemotingClient.getInstance().destroy();
            TmNettyRemotingClient.getInstance().destroy();
            System.clearProperty("service.default.grouplist");
        }
    }
}
  • extracted("jdbc:tc:postgresql:17.1-bookworm://test/demo_ds_0?TC_INITSCRIPT=init.sql") will succeed because the setting of the System Properties service.default.grouplist is successfully listened to. But extracted("jdbc:tc:postgresql:17.1-bookworm://test/demo_ds_1?TC_INITSCRIPT=init.sql") will fail because updates to the System Properties service.default.grouplist are not being watched.
[ERROR] 2024-12-01 11:26:42.917 [main] o.a.s.c.r.n.NettyClientChannelManager - 0304 register RM failed.
org.apache.seata.common.exception.FrameworkException: can not connect to services-server.
        at org.apache.seata.core.rpc.netty.NettyClientBootstrap.getNewChannel(NettyClientBootstrap.java:181)
        at org.apache.seata.core.rpc.netty.NettyPoolableFactory.makeObject(NettyPoolableFactory.java:58)
        at org.apache.seata.core.rpc.netty.NettyPoolableFactory.makeObject(NettyPoolableFactory.java:34)
        at org.apache.commons.pool.impl.GenericKeyedObjectPool.borrowObject(GenericKeyedObjectPool.java:1220)

How it could be?

A clear and concise description of what you want to happen. You can explain more about input of the feature, and output of it.

  • Seata Client should allow dynamic monitoring of changes in service.default.grouplist.
  • I'm not sure if this is one of the TODOs for Seata Multi-Client Optimization #6614, but it's really not intuitive if creating and destroying multiple Seata Clients needs to be done in different Maven modules.

Other related information

Add any other context or screenshots about the feature request here.

@funky-eyes
Copy link
Contributor

Do you mean that during runtime, there could be multiple TMs or RMs performing different initializations? Regarding transaction groups, we don't dynamically listen because we believe that at the application level, there is only one RM or TM running. As long as the RM client is registered, regardless of how many resources it has internally, the Seata server can issue the second-phase instructions through the corresponding channel. Therefore, it seems that there is no scenario where related listening is needed.

@linghengqian
Copy link
Member Author

Right. Or another possibility is, is there any way for me to completely shut down Seata Client so that it can be reinitialized? It seems that Seata Client starts multiple uncontrolled timing java methods internally.

@funky-eyes
Copy link
Contributor

TmNettyRemotingClient.getInstance().destroy();
RmNettyRemotingClient.getInstance().destroy();
ConfigurationFactory.reload();

You can try using this code

@linghengqian
Copy link
Member Author

@funky-eyes
Copy link
Contributor

Yes, you can close this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants