-
Notifications
You must be signed in to change notification settings - Fork 1k
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
feat: add ASSERT TOPIC command #9066
Conversation
@@ -89,6 +89,7 @@ statement | |||
| CREATE TYPE (IF NOT EXISTS)? identifier AS type #registerType | |||
| DROP TYPE (IF EXISTS)? identifier #dropType | |||
| ALTER (STREAM | TABLE) sourceName alterOption (',' alterOption)* #alterSource | |||
| ASSERT TOPIC identifier (WITH tableProperties)? timeout? #assertTopic |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to ask... ASSERT TOPIC
needs to be here to be processed with other DDL commands instead of with assertStatement
below? (That's my guess; just validating.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, the ones below are only used by YATT.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you adding the "NOT" support in this PR or a separate one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's going in a separate one.
} | ||
}, containsString( | ||
"Mismatched configuration for topic X: For config partitions, expected apples got 1\n" | ||
+ "Mismatched configuration for topic X: For config replicas, expected 100 got 1\n" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the expected text backwards? The stream was created with (1,1) and (apples, 100) were offered, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
its (the assert statement) expected 100, got 1 (from the topic instead)
i can see how the wording is ambiguous. maybe something like would be clearer:
For config partitions, 100 was asserted, but the actual value was 1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I read it backwards yesterday!
public void shouldPrintAssertTopicResult() { | ||
// Given: | ||
final KsqlEntityList entities = new KsqlEntityList(ImmutableList.of( | ||
new AssertTopicEntity("statement", "topic") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As an optional thing, it may be worth considering a new other than "topic" for the topic. That avoids the approved version being "Topic topic exists."
shrugs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lol okay. Done.
@@ -661,6 +661,12 @@ public class KsqlConfig extends AbstractConfig { | |||
private static final boolean KSQL_ENDPOINT_MIGRATE_QUERY_DEFAULT = true; | |||
private static final String KSQL_ENDPOINT_MIGRATE_QUERY_DOC | |||
= "Migrates the /query endpoint to use the same handler as /query-stream."; | |||
public static final String KSQL_ASSERT_TOPIC_DEFAULT_TIMEOUT_MS |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need/want to document this setting?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I plan on doing docs all in one go. It saves us the trouble of having to revert things in case the full project doesn't land in the next release.
return false; | ||
} | ||
final AssertTopic that = (AssertTopic) o; | ||
return topic.equals(that.topic) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to check that the location
is the same?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, location
just refers to what line/position the ASSERT
token was found, so it doesn't really matter here.
@@ -41,7 +41,7 @@ public class GrammarTokenExporterTest { | |||
"CATALOG", "PROPERTIES", "BEGINNING", "UNSET", "RUN", "SCRIPT", "DECIMAL", | |||
"KEY", "CONNECTOR", "CONNECTORS", "SINK", "SOURCE", "NAMESPACE", "MATERIALIZED", | |||
"VIEW", "PRIMARY", "REPLACE", "ASSERT", "ADD", "ALTER", "VARIABLES", "PLUGINS", "HEADERS", | |||
"HEADER", "SYSTEM", "IF", "EQ", "NEQ", "LT", "LTE", "GT", "GTE", "PLUS", "MINUS", "ASTERISK", | |||
"HEADER", "SYSTEM", "TIMEOUT", "IF", "EQ", "NEQ", "LT", "LTE", "GT", "GTE", "PLUS", "MINUS", "ASTERISK", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's our procedure for adding new reserved words? I imagine we do want to note that somewhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TIMEOUT
is a non-reserved word. This is just a list of all the grammar tokens.
RetryUtil.retryWithBackoff( | ||
timeout / RETRY_MS, | ||
RETRY_MS, | ||
RETRY_MS, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be timeout. If I'm reading code correctly, there'd only be one retry with the code as-is. (I'm skimming, so happy to be wrong.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
public static void retryWithBackoff(
final int maxRetries,
final int initialWaitMs,
final int maxWaitMs,
final Runnable runnable,
final Class<?>... passThroughExceptions)
The retryWithBackoff
method increases the retry timeout between each retry. It starts at initialWaitMs
and then inceases to 2*initialWaitMs
and then 4*initialWaitMs
etc until it reaches maxWait
. So if we keep initialWaitMs
== maxWaitMs
then it will retry every initialWaitMs
ms until we reach maxRetries
.
|
||
if (topicExists) { | ||
final int partitions = client.describeTopic(topic).partitions().size(); | ||
final int replicas = client.describeTopic(topic).partitions().get(0).replicas().size(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be better to factor out the call to client.describeTopic(topic).partitions()
? (Not sure if the metadata is cached or what.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call, that's another api call. Done.
final int partitions = client.describeTopic(topic).partitions().size(); | ||
final int replicas = client.describeTopic(topic).partitions().get(0).replicas().size(); | ||
final List<String> configErrors = new ArrayList<>(); | ||
config.forEach((k, v) -> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a non-blocking comment, the part of me that's an Scala/FP junkie would offer that it may be an interesting exercise to see if it is easy to switch to a "map" (or maybe a flatmap) and collect the result for the errors.
This code works and is clear, so no obligation to try that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, thank you for collecting all the errors!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leaving it as is because I tried that end it ended up getting messier :(
@@ -555,6 +556,7 @@ public static List<String> makeWsRequest( | |||
|
|||
mediaType.ifPresent(mt -> headers.add(ACCEPT.toString(), mt)); | |||
contentType.ifPresent(ct -> headers.add(CONTENT_TYPE.toString(), ct)); | |||
headers.add(EXPIRES.toString(), "Wed, 13 Apr 2022 07:28:00 GMT"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need this header? Also, isn't it expired? I'm confused.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
whoops that was from something completely different I was testing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks pretty reasonable. Happy to approve after another round of discussions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the discussion! LGTM!
Description
Adds
ASSERT TOPIC
command to ksqlDB. See discussion hereTesting done
Unit + integration tests
Reviewer checklist