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

feat: add ASSERT TOPIC command #9066

Merged
merged 8 commits into from
Apr 28, 2022
Merged

feat: add ASSERT TOPIC command #9066

merged 8 commits into from
Apr 28, 2022

Conversation

jzaralim
Copy link
Contributor

Description

Adds ASSERT TOPIC command to ksqlDB. See discussion here

Testing done

Unit + integration tests

Reviewer checklist

  • Ensure docs are updated if necessary. (eg. if a user visible feature is being added or changed).
  • Ensure relevant issues are linked (description should include text like "Fixes #")

@jzaralim jzaralim requested a review from a team as a code owner April 26, 2022 22:32
@jzaralim jzaralim marked this pull request as draft April 27, 2022 08:51
@@ -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
Copy link
Member

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.)

Copy link
Contributor Author

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.

Copy link
Member

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?

Copy link
Contributor Author

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"
Copy link
Member

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?

Copy link
Contributor Author

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

Copy link
Member

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!

@jzaralim jzaralim marked this pull request as ready for review April 27, 2022 18:57
public void shouldPrintAssertTopicResult() {
// Given:
final KsqlEntityList entities = new KsqlEntityList(ImmutableList.of(
new AssertTopicEntity("statement", "topic")
Copy link
Member

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

Copy link
Contributor Author

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
Copy link
Member

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?

Copy link
Contributor Author

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)
Copy link
Member

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?

Copy link
Contributor Author

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",
Copy link
Member

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.

Copy link
Contributor Author

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,
Copy link
Member

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.)

Copy link
Contributor Author

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();
Copy link
Member

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.)

Copy link
Contributor Author

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) -> {
Copy link
Member

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.

Copy link
Member

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!

Copy link
Contributor Author

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");
Copy link
Member

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.

Copy link
Contributor Author

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

Copy link
Member

@jnh5y jnh5y left a 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.

Copy link
Member

@jnh5y jnh5y left a 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!

@jzaralim jzaralim merged commit cd5254f into master Apr 28, 2022
@jzaralim jzaralim deleted the assert-topic branch April 28, 2022 21:09
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

Successfully merging this pull request may close these issues.

2 participants