AS3, optional type annotation, and strict mode

本文探讨了ActionScript 3中类型注释的作用及其实现细节,通过具体示例对比了不同类型的函数调用产生的代码差异。文章还讨论了严格模式与标准模式下编译器的行为区别,并对编译器的类型推断能力和运行时性能优化进行了分析。
Boy, this is my first English post on this blog. I wish I had the time to write more English and Japanses posts. Anyway here we go.

Those who have been using ActionScript 3 would have noticed its optional type annotations. So what do we get from being explicit about types? It's obvious that, by stating the programs' invariants through type annotation, type errors can be reported earlier (at compile time) than they would have been otherwise (at runtime). But what else? Does explicit typing yield better runtime performance too?

On the current implementation of Adobe's ActionScript 3 compiler, the answer to that may just be a _no_. Even though Flex SDK and Tamarin are both open source, which means that we can get full sources to the whole compiler+vm suite to get AS3 running, it's still hard to figure things out just by browsing through the code without detailed documentations. So I'm just gonna do some superficial tests to see what's going on in the AS3 compiler.

=======================================================================================================

When compiling AS3 source code, there are two compilation modes: the standard mode and the strict mode. In standard mode, everything's supposed to be compatible to the good old ECMA-262 version 3 spec, so we should be able to safely assume that the type annotations in standard mode doesn't do much. In strict mode, however, some type checks can be done at compile time, so that: we can't assign to a variable not yet declared, neither can we call a function with parameters of imcompatible types.

According to the ES4 wiki, [url=http://wiki.ecmascript.org/doku.php?id=proposals:strict_and_standard_modes]Strict and Standard compilation modes[/url], strict mode is [i]"only meant as a way for programmers to indicate their desire for more extensive and conservative error analysis"[/i], and does not imply optimizations, although implementation can take advantage of the type information to produce better code.

So let's take a look at this sample code snippet, to see how type annotations affect type checking and instruction selection in Adobe's AS3 compiler:
test.as:
package {

class TestClass {
function foo(x : int, y : int) : int {
return x + y;
}

function goo(x, y) {
return foo(x, y);
}

function hoo(x, y : String) {
return x + y;
}

function ioo(x : int, y : int) {
var i = x + y;
return i;
}

function joo(x : int, y : int) {
var i : int = x + y;
return i;
}
}

var c = new TestClass();
var i = c.goo(1, "2");
print(i); // 3
i = c.hoo(1, "2");
print(i); // 12
i = c.ioo(1, "2");
print(i); // 3
}

(compiled with asc.jar from Flex 3 SDK, with the command:
java -jar asc.jar -import builtin.abc -import toplevel.abc -m -strict test.as
builtin.abc and toplevel.abc are from Tamarin, 2007/10/31)

The methods in the code snippet are pretty much the same: they *add up* the two parameters. Foo() is fully type annotated, goo() is totally unannotated, where as the other methods are partially annotated.
Note that there are two AVM2 instructions that does the operation of "add": one is the general "add", the other is "add_i", which adds up two integers.
As stated in [url=http://www.adobe.com/devnet/actionscript/articles/avm2overview.pdf]ActionScript Virtual Machine 2 Overview[/url], the semantics of add and add_i are:
[quote="ActionScript Virtual Machine 2 (AVM2) Overview"][Append][Append][Append] method.
4. If none of the above apply, convert value1 and value2 to primitives. This is done by calling ToPrimitive with no hint. This results in value1_primitive and value2_primitive. If value1_primitive or value2_primitive is a String then convert both to Strings using the ToString algorithm (ECMA-262 section 9.8), concatenate the results, and set value3 to the concatenated String. Otherwise convert both to Numbers using the ToNumber algorithm (ECMA-262 section 9.3), add the results, and set value3 to the result of the addition.
Push value3 onto the stack.
Notes
For more information, see ECMA-262 section 11.6 (“Additive Operators”) and ECMA-357 section 11.4.[/quote]
[quote="ActionScript Virtual Machine 2 (AVM2) Overview"]add_i
Operation
Add two integer values.
Format
add_i
Forms
add_i = 197 (0xc5)
Stack
…, value1, value2 => …, value3
Description
Pop value1 and value2 off of the stack and convert them to int values using the ToInt32 algorithm (ECMA-262 section 9.5). Add the two int values and push the result onto the stack.[/quote]
Both instructions aren't really low-level enough. Whatever parameters passed in, both instructions include the semantics to do a type check/implicit type convertion first, then add the two operands, and finally pushing the result back onto the evaluation stack. Anyway, if it is known that both the operands are ints, I reckon it should be better to choose add_i than add. But that's not the case here, Adobe's AS3 compiler always generated code using add.

Take a closer look at the code generated for foo().
The method's generated signature is:
[code] 1. MethodInfo param_count=2 return_type=1 param_types={ 1 1 } debug_name_index=2 needs_arguments=false need_rest=false needs_activation=false has_optional=false ignore_rest=false native=false has_param_names =false -> 1[/code]
The return type and parameter types are all int, correct.
The method's body:
[code]MethodBody max_stack=2 max_locals=3 scope_depth=4 max_scope=5 code_length=6 traits_count=0 -> 1[/code]
[code]// ++StartMethod foo$0

LoadThis
0:Getlocal0 [1]

PushScope
1:Pushscope [0]

LoadRegister 1, int
2:Getlocal1 [1]

LoadRegister 2, int
3:Getlocal2 [2]

InvokeBinary BinaryPlusOp
4:Add [1]

Return
5:Returnvalue [0]

// --FinishMethod foo$0 TestClass/foo[/code]
So even when fully type annotated as in foo(), the compiler chooses add instead of add_i. Actually the compiler seem to generate the same code for foo()'s method body whatever the compilation mode.

For goo(), we can see that calling goo() with (1, "2") yields a number 3. The string "2" is implicitly converted into int upon calling foo() in goo(), even if that wasn't the programmer's intention.
The compiler doesn't reject methods calls where formal parameters' types and actual parameters' types aren't exactly the same. The types are considered "compatible" if there's a way to implicitly convert from the source type to the target type. So unless we do something like this:
class A { }
class B { }
function test(a : A) {
print("A");
}
test(new B()); // compile time error
// [Compiler] Error #1067: Implicit coercion of a value of type B to an unrelated type A.

the compiler's gonna be "forgiving" enough not to warn you that implicit conversions have been done. Not to mention, code like this will also compile, whatever the compilation mode:
c.ioo(1);

No errors, no warnings. Not until you run the code will you see the argument error:
[quote]ArgumentError: Error #1063[/quote]

I thought strict mode was supposed to be less forgiving than this...well, I'm wrong.

It's easy to see that the compiler doesn't do type inference at all. In ioo(), where I didn't annotate the local variable's type, the compiler adds a coerce instruction after the add:
[code]// ++StartMethod ioo$0

LoadThis
0:Getlocal0 [1]

PushScope
1:Pushscope [0]

LoadRegister 1, int
2:Getlocal1 [1]

LoadRegister 2, int
3:Getlocal2 [2]

InvokeBinary BinaryPlusOp
4:Add [1]

CheckType *
5:Coerce.o [1] // coerce here

StoreRegister 3, *
6:Setlocal3 [0]

LoadRegister 3, *
7:Getlocal3 [1]

Return
8:Returnvalue [0]

// --FinishMethod ioo$0 TestClass/ioo[/code]
Again, the code generated for ioo()'s method body is the same whatever the compilation mode. Overall, there's only little difference between code generated in strict mode or standard mode.

Haven't run any benchmarks for differently annotated code, I'd just guess from the code generated that strict mode with annotated types in AS3 doesn't imply better runtime performance. I'm asking [url=http://blogs.adobe.com/fcheng/]Francis Cheng[/url] on this, and see if he can give us more detail on optional type annotations and strict mode.

I thought we can take advantage of the declared types and at least reduce some of these redundant type checks/coerces. Adobe's AS3 compiler doesn't do that currently. And there should be a reason behind it, which I don't know. Maybe digging into the source code will give me a better picture...

=======================================================================================================

The only reason I can come up with is, the optimization on reducing dynamic type checking is not done at compile time, and is instead done at runtime, through a tracing-JIT. [url=http://www.bluishcoder.co.nz/2008/02/quick-introduction-to-tamarin-tracing.html]Tamarin-tracing[/url] is the one that
[quote]traces code executing during hotspots and compiles it so when those hotspots are entered again the compiled code is run instead. It traces each statement executed, including within other function calls, and this entire execution path is compiled.[/quote]
Maybe the JITter knows how to reduce all those redundant type checks on frequently used types, so no matter what compilation mode you're using, you always benefit from the runtime.

=======================================================================================================

The Impact of Optional Type Information on JIt Compilation of Dynammically Typed Languages
2025-11-05 15:19:23.442 [main] INFO o.w.a.web.api.WebApiApplication - Starting WebApiApplication using Java 17.0.16 with PID 24352 (D:\world_aquatics_0922\world-aquatics-api\world-aquatics-web-api\target\classes started by LZY in D:\world_aquatics_0922) 2025-11-05 15:19:23.444 [main] INFO o.w.a.web.api.WebApiApplication - No active profile set, falling back to 1 default profile: "default" 2025-11-05 15:19:25.147 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode 2025-11-05 15:19:25.149 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data Elasticsearch repositories in DEFAULT mode. 2025-11-05 15:19:25.166 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 13 ms. Found 0 Elasticsearch repository interfaces. 2025-11-05 15:19:25.171 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode 2025-11-05 15:19:25.171 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data Reactive Elasticsearch repositories in DEFAULT mode. 2025-11-05 15:19:25.173 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 1 ms. Found 0 Reactive Elasticsearch repository interfaces. 2025-11-05 15:19:25.183 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode 2025-11-05 15:19:25.184 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data Redis repositories in DEFAULT mode. 2025-11-05 15:19:25.192 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 1 ms. Found 0 Redis repository interfaces. 2025-11-05 15:19:25.879 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port 8081 (http) 2025-11-05 15:19:25.891 [main] INFO o.a.catalina.core.StandardService - Starting service [Tomcat] 2025-11-05 15:19:25.891 [main] INFO o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/10.1.16] 2025-11-05 15:19:25.960 [main] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext 2025-11-05 15:19:25.960 [main] INFO o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 2480 ms 2025-11-05 15:19:25.981 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Found key 'jwt.secret' in PropertySource 'environmentProperties' with value of type String 2025-11-05 15:19:25.982 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Found key 'jwt.expire' in PropertySource 'environmentProperties' with value of type String Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter. Can not find table primary key in Class: "org.world.aquatics.common.domain.SysRoleMenuTbl". 2025-11-05 15:19:26.770 [main] WARN c.b.m.c.injector.DefaultSqlInjector - class org.world.aquatics.common.domain.SysRoleMenuTbl ,Not found @TableId annotation, Cannot use Mybatis-Plus 'xxById' Method. Can not find table primary key in Class: "org.world.aquatics.common.domain.SysUserRoleTbl". 2025-11-05 15:19:26.800 [main] WARN c.b.m.c.injector.DefaultSqlInjector - class org.world.aquatics.common.domain.SysUserRoleTbl ,Not found @TableId annotation, Cannot use Mybatis-Plus 'xxById' Method. Initialization Sequence datacenterId:11 workerId:14 _ _ |_ _ _|_. ___ _ | _ | | |\/|_)(_| | |_\ |_)||_|_\ / | 3.5.5 2025-11-05 15:19:27.193 [main] INFO o.w.a.s.config.ElasticsearchConfig - Elasticsearch 配置加载: host={172.18.56.53}, port={9201} 2025-11-05 15:19:27.520 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Found key 'spring.kafka.bootstrap-servers' in PropertySource 'environmentProperties' with value of type String 2025-11-05 15:19:27.521 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Found key 'spring.kafka.consumer.group-id' in PropertySource 'environmentProperties' with value of type String 2025-11-05 15:19:27.786 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Found key 'springdoc.api-docs.path' in PropertySource 'environmentProperties' with value of type String 2025-11-05 15:19:27.786 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Found key 'springdoc.api-docs.path' in PropertySource 'environmentProperties' with value of type String 2025-11-05 15:19:27.789 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Found key 'springdoc.api-docs.path' in PropertySource 'environmentProperties' with value of type String 2025-11-05 15:19:27.790 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Found key 'springdoc.api-docs.path' in PropertySource 'environmentProperties' with value of type String 2025-11-05 15:19:27.791 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Found key 'springdoc.swagger-ui.path' in PropertySource 'environmentProperties' with value of type String 2025-11-05 15:19:27.791 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Found key 'springdoc.swagger-ui.path' in PropertySource 'environmentProperties' with value of type String 2025-11-05 15:19:27.791 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Found key 'springdoc.api-docs.path' in PropertySource 'environmentProperties' with value of type String 2025-11-05 15:19:27.902 [main] INFO o.s.s.web.DefaultSecurityFilterChain - Will secure any request with [org.springframework.security.web.session.DisableEncodeUrlFilter@476a2819, org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@279ab15e, org.springframework.security.web.context.SecurityContextHolderFilter@3bbc47c9, org.springframework.security.web.header.HeaderWriterFilter@62a81453, org.springframework.web.filter.CorsFilter@571c2ed8, org.springframework.security.web.authentication.logout.LogoutFilter@188ae8d2, org.world.aquatics.web.api.sso.JwtRequestFilter@2055833f, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@144dc2f7, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@403cff1c, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@5810772a, org.springframework.security.web.session.SessionManagementFilter@690677de, org.springframework.security.web.access.ExceptionTranslationFilter@102aa5fc, org.springframework.security.web.access.intercept.AuthorizationFilter@eddc9bb] 2025-11-05 15:19:28.324 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port 8081 (http) with context path '' 2025-11-05 15:19:28.363 [main] INFO o.a.k.c.consumer.ConsumerConfig - ConsumerConfig values: allow.auto.create.topics = true auto.commit.interval.ms = 5000 auto.include.jmx.reporter = true auto.offset.reset = earliest bootstrap.servers = [172.18.56.53:9092] check.crcs = true client.dns.lookup = use_all_dns_ips client.id = consumer-world-aquatics-group-1 client.rack = connections.max.idle.ms = 540000 default.api.timeout.ms = 60000 enable.auto.commit = false exclude.internal.topics = true fetch.max.bytes = 52428800 fetch.max.wait.ms = 500 fetch.min.bytes = 1 group.id = world-aquatics-group group.instance.id = null heartbeat.interval.ms = 3000 interceptor.classes = [] internal.leave.group.on.close = true internal.throw.on.fetch.stable.offset.unsupported = false isolation.level = read_uncommitted key.deserializer = class org.apache.kafka.common.serialization.StringDeserializer max.partition.fetch.bytes = 1048576 max.poll.interval.ms = 300000 max.poll.records = 500 metadata.max.age.ms = 300000 metric.reporters = [] metrics.num.samples = 2 metrics.recording.level = INFO metrics.sample.window.ms = 30000 partition.assignment.strategy = [class org.apache.kafka.clients.consumer.RangeAssignor, class org.apache.kafka.clients.consumer.CooperativeStickyAssignor] receive.buffer.bytes = 65536 reconnect.backoff.max.ms = 1000 reconnect.backoff.ms = 50 request.timeout.ms = 30000 retry.backoff.ms = 100 sasl.client.callback.handler.class = null sasl.jaas.config = null sasl.kerberos.kinit.cmd = /usr/bin/kinit sasl.kerberos.min.time.before.relogin = 60000 sasl.kerberos.service.name = null sasl.kerberos.ticket.renew.jitter = 0.05 sasl.kerberos.ticket.renew.window.factor = 0.8 sasl.login.callback.handler.class = null sasl.login.class = null sasl.login.connect.timeout.ms = null sasl.login.read.timeout.ms = null sasl.login.refresh.buffer.seconds = 300 sasl.login.refresh.min.period.seconds = 60 sasl.login.refresh.window.factor = 0.8 sasl.login.refresh.window.jitter = 0.05 sasl.login.retry.backoff.max.ms = 10000 sasl.login.retry.backoff.ms = 100 sasl.mechanism = GSSAPI sasl.oauthbearer.clock.skew.seconds = 30 sasl.oauthbearer.expected.audience = null sasl.oauthbearer.expected.issuer = null sasl.oauthbearer.jwks.endpoint.refresh.ms = 3600000 sasl.oauthbearer.jwks.endpoint.retry.backoff.max.ms = 10000 sasl.oauthbearer.jwks.endpoint.retry.backoff.ms = 100 sasl.oauthbearer.jwks.endpoint.url = null sasl.oauthbearer.scope.claim.name = scope sasl.oauthbearer.sub.claim.name = sub sasl.oauthbearer.token.endpoint.url = null security.protocol = PLAINTEXT security.providers = null send.buffer.bytes = 131072 session.timeout.ms = 45000 socket.connection.setup.timeout.max.ms = 30000 socket.connection.setup.timeout.ms = 10000 ssl.cipher.suites = null ssl.enabled.protocols = [TLSv1.2, TLSv1.3] ssl.endpoint.identification.algorithm = https ssl.engine.factory.class = null ssl.key.password = null ssl.keymanager.algorithm = SunX509 ssl.keystore.certificate.chain = null ssl.keystore.key = null ssl.keystore.location = null ssl.keystore.password = null ssl.keystore.type = JKS ssl.protocol = TLSv1.3 ssl.provider = null ssl.secure.random.implementation = null ssl.trustmanager.algorithm = PKIX ssl.truststore.certificates = null ssl.truststore.location = null ssl.truststore.password = null ssl.truststore.type = JKS value.deserializer = class org.apache.kafka.common.serialization.StringDeserializer 2025-11-05 15:19:28.445 [main] INFO o.a.kafka.common.utils.AppInfoParser - Kafka version: 3.6.0 2025-11-05 15:19:28.446 [main] INFO o.a.kafka.common.utils.AppInfoParser - Kafka commitId: 60e845626d8a465a 2025-11-05 15:19:28.446 [main] INFO o.a.kafka.common.utils.AppInfoParser - Kafka startTimeMs: 1762327168444 2025-11-05 15:19:28.448 [main] INFO o.s.k.c.DefaultKafkaConsumerFactory$ExtendedKafkaConsumer - [Consumer clientId=consumer-world-aquatics-group-1, groupId=world-aquatics-group] Subscribed to topic(s): world-aquatics-topic 2025-11-05 15:19:28.462 [main] INFO o.w.a.web.api.WebApiApplication - Started WebApiApplication in 5.359 seconds (process running for 7.57) === Config File Loading Information === Active profiles: [] Default profiles: [default] 2025-11-05 15:19:28.464 [main] INFO o.w.a.web.api.WebApiApplication - WebApiApplication启动成功! 2025-11-05 15:19:28.857 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO org.apache.kafka.clients.Metadata - [Consumer clientId=consumer-world-aquatics-group-1, groupId=world-aquatics-group] Cluster ID: seNzt9cQRVW5qmRcTDdWIw 2025-11-05 15:19:28.858 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO o.a.k.c.c.i.ConsumerCoordinator - [Consumer clientId=consumer-world-aquatics-group-1, groupId=world-aquatics-group] Discovered group coordinator 172.18.56.53:9092 (id: 2147483646 rack: null) 2025-11-05 15:19:28.859 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO o.a.k.c.c.i.ConsumerCoordinator - [Consumer clientId=consumer-world-aquatics-group-1, groupId=world-aquatics-group] (Re-)joining group 2025-11-05 15:19:28.872 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO o.a.k.c.c.i.ConsumerCoordinator - [Consumer clientId=consumer-world-aquatics-group-1, groupId=world-aquatics-group] Request joining group due to: need to re-join with the given member-id: consumer-world-aquatics-group-1-3cdba838-80cb-4630-9f17-37c5002ee331 2025-11-05 15:19:28.873 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO o.a.k.c.c.i.ConsumerCoordinator - [Consumer clientId=consumer-world-aquatics-group-1, groupId=world-aquatics-group] Request joining group due to: rebalance failed due to 'The group member needs to have a valid member id before actually entering a consumer group.' (MemberIdRequiredException) 2025-11-05 15:19:28.873 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO o.a.k.c.c.i.ConsumerCoordinator - [Consumer clientId=consumer-world-aquatics-group-1, groupId=world-aquatics-group] (Re-)joining group 2025-11-05 15:19:31.882 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO o.a.k.c.c.i.ConsumerCoordinator - [Consumer clientId=consumer-world-aquatics-group-1, groupId=world-aquatics-group] Successfully joined group with generation Generation{generationId=1, memberId='consumer-world-aquatics-group-1-3cdba838-80cb-4630-9f17-37c5002ee331', protocol='range'} 2025-11-05 15:19:31.887 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO o.a.k.c.c.i.ConsumerCoordinator - [Consumer clientId=consumer-world-aquatics-group-1, groupId=world-aquatics-group] Finished assignment for group at generation 1: {consumer-world-aquatics-group-1-3cdba838-80cb-4630-9f17-37c5002ee331=Assignment(partitions=[world-aquatics-topic-0])} 2025-11-05 15:19:31.901 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO o.a.k.c.c.i.ConsumerCoordinator - [Consumer clientId=consumer-world-aquatics-group-1, groupId=world-aquatics-group] Successfully synced group in generation Generation{generationId=1, memberId='consumer-world-aquatics-group-1-3cdba838-80cb-4630-9f17-37c5002ee331', protocol='range'} 2025-11-05 15:19:31.901 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO o.a.k.c.c.i.ConsumerCoordinator - [Consumer clientId=consumer-world-aquatics-group-1, groupId=world-aquatics-group] Notifying assignor about the new Assignment(partitions=[world-aquatics-topic-0]) 2025-11-05 15:19:31.902 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO o.a.k.c.c.i.ConsumerCoordinator - [Consumer clientId=consumer-world-aquatics-group-1, groupId=world-aquatics-group] Adding newly assigned partitions: world-aquatics-topic-0 2025-11-05 15:19:31.910 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO o.a.k.c.c.i.ConsumerCoordinator - [Consumer clientId=consumer-world-aquatics-group-1, groupId=world-aquatics-group] Found no committed offset for partition world-aquatics-topic-0 2025-11-05 15:19:31.918 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO o.a.k.c.c.i.SubscriptionState - [Consumer clientId=consumer-world-aquatics-group-1, groupId=world-aquatics-group] Resetting offset for partition world-aquatics-topic-0 to position FetchPosition{offset=0, offsetEpoch=Optional.empty, currentLeader=LeaderAndEpoch{leader=Optional[172.18.56.53:9092 (id: 1 rack: null)], epoch=0}}. 2025-11-05 15:19:31.919 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] INFO o.s.k.l.KafkaMessageListenerContainer - world-aquatics-group: partitions assigned: [world-aquatics-topic-0] 这一段日志输出表明了什么问题?需要怎么去解决这个问题?
最新发布
11-06
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值