Skip to content

Commit

Permalink
feat: Improve local subscriptions (#3028)
Browse files Browse the repository at this point in the history
  • Loading branch information
stuartwdouglas authored Oct 14, 2024
1 parent 90386c0 commit 1a5602f
Show file tree
Hide file tree
Showing 8 changed files with 53 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import io.quarkus.logging.Log;
import xyz.block.ftl.Export;
import xyz.block.ftl.Subscription;
import xyz.block.ftl.Topic;
import xyz.block.ftl.TopicDefinition;
import xyz.block.ftl.Verb;
Expand All @@ -14,14 +15,19 @@ interface TestTopic extends Topic<PubSubEvent> {

}

@TopicDefinition("localTopic")
interface LocalTopic extends Topic<PubSubEvent> {

}

@Export
@TopicDefinition("topic2")
interface Topic2 extends Topic<PubSubEvent> {

}

@Verb
void publishTen(TestTopic testTopic) throws Exception {
void publishTen(LocalTopic testTopic) throws Exception {
for (var i = 0; i < 10; ++i) {
var t = java.time.ZonedDateTime.now();
Log.infof("Publishing %s", t);
Expand All @@ -42,4 +48,9 @@ void publishOneToTopic2(Topic2 topic2) throws Exception {
Log.infof("Publishing %s", t);
topic2.publish(new PubSubEvent().setTime(t));
}

@Subscription(topicClass = LocalTopic.class, name = "localSubscription")
public void local(TestTopic testTopic, PubSubEvent event) {
testTopic.publish(event);
}
}
5 changes: 2 additions & 3 deletions docs/content/docs/reference/pubsub.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,14 +116,13 @@ There are two ways to subscribe to a topic. The first is to declare a method wit
subscribing to a topic inside the same module:

```java
@Subscription(topic = "invoices", name = "invoicesSubscription")
@Subscription(topicClass = InvoiceTopic.class, name = "invoicesSubscription")
public void consumeInvoice(Invoice event) {
// ...
}
```

This is ok, but it requires the use of string constants for the topic name, which can be error-prone. If you are subscribing to a topic from
another module, FTL will generate a type-safe subscription meta annotation you can use to subscribe to the topic:
If you are subscribing to a topic from another module, FTL will generate a type-safe subscription meta annotation you can use to subscribe to the topic:

```java
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import xyz.block.ftl.LeaseClient;
import xyz.block.ftl.Secret;
import xyz.block.ftl.Subscription;
import xyz.block.ftl.TopicDefinition;
import xyz.block.ftl.TypeAlias;
import xyz.block.ftl.TypeAliasMapper;
import xyz.block.ftl.Verb;
Expand All @@ -33,4 +34,5 @@ private FTLDotNames() {
public static final DotName SUBSCRIPTION = DotName.createSimple(Subscription.class);
public static final DotName LEASE_CLIENT = DotName.createSimple(LeaseClient.class);
public static final DotName GENERATED_REF = DotName.createSimple(GeneratedRef.class);
public static final DotName TOPIC_DEFINITION = DotName.createSimple(TopicDefinition.class);
}
Original file line number Diff line number Diff line change
Expand Up @@ -620,10 +620,10 @@ private boolean setDeclExport(String name, boolean export) {
var existing = decls.get(name);
if (existing != null) {
if (existing.hasData()) {
var merged = existing.getData().toBuilder().setExport(export).build();
var merged = existing.getData().toBuilder().setExport(export || existing.getData().getExport()).build();
decls.put(name, Decl.newBuilder().setData(merged).build());
} else if (existing.hasTypeAlias()) {
var merged = existing.getTypeAlias().toBuilder().setExport(export).build();
var merged = existing.getTypeAlias().toBuilder().setExport(export || existing.getData().getExport()).build();
decls.put(name, Decl.newBuilder().setTypeAlias(merged).build());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.AnnotationValue;
import org.jboss.jandex.DotName;
import org.jboss.jandex.IndexView;

import io.quarkus.builder.item.SimpleBuildItem;
import xyz.block.ftl.Topic;

public final class SubscriptionMetaAnnotationsBuildItem extends SimpleBuildItem {

Expand All @@ -23,13 +25,33 @@ public Map<DotName, SubscriptionAnnotation> getAnnotations() {
public record SubscriptionAnnotation(String module, String topic, String name) {
}

public static SubscriptionAnnotation fromJandex(AnnotationInstance subscriptions, String currentModuleName) {
AnnotationValue moduleValue = subscriptions.value("module");
public static SubscriptionAnnotation fromJandex(IndexView indexView, AnnotationInstance subscriptions,
String currentModuleName) {

AnnotationValue moduleValue = subscriptions.value("module");
AnnotationValue topicValue = subscriptions.value("topic");
AnnotationValue topicClassValue = subscriptions.value("topicClass");
String topicName;
if (topicValue != null && !topicValue.asString().isEmpty()) {
if (topicClassValue != null && !topicClassValue.asClass().name().toString().equals(Topic.class.getName())) {
throw new IllegalArgumentException("Cannot specify both topic and topicClass");
}
topicName = topicValue.asString();
} else if (topicClassValue != null && !topicClassValue.asClass().name().toString().equals(Topic.class.getName())) {
var topicClass = indexView.getClassByName(topicClassValue.asClass().name());
AnnotationInstance annotation = topicClass.annotation(FTLDotNames.TOPIC_DEFINITION);
if (annotation == null) {
throw new IllegalArgumentException(
"topicClass must be annotated with @TopicDefinition for subscription " + subscriptions);
}
topicName = annotation.value().asString();
} else {
throw new IllegalArgumentException("Either topic or topicClass must be specified on " + subscriptions);
}
return new SubscriptionMetaAnnotationsBuildItem.SubscriptionAnnotation(
moduleValue == null || moduleValue.asString().isEmpty() ? currentModuleName
: moduleValue.asString(),
subscriptions.value("topic").asString(),
topicName,
subscriptions.value("name").asString());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ SubscriptionMetaAnnotationsBuildItem subscriptionAnnotations(CombinedIndexBuildI
continue;
}
annotations.put(subscriptions.target().asClass().name(),
SubscriptionMetaAnnotationsBuildItem.fromJandex(subscriptions, moduleNameBuildItem.getModuleName()));
SubscriptionMetaAnnotationsBuildItem.fromJandex(combinedIndexBuildItem.getComputingIndex(), subscriptions,
moduleNameBuildItem.getModuleName()));
}
return new SubscriptionMetaAnnotationsBuildItem(annotations);
}
Expand All @@ -52,7 +53,7 @@ public void registerSubscriptions(CombinedIndexBuildItem index,
AdditionalBeanBuildItem.Builder beans = AdditionalBeanBuildItem.builder().setUnremovable();
var moduleName = moduleNameBuildItem.getModuleName();
for (var subscription : index.getIndex().getAnnotations(FTLDotNames.SUBSCRIPTION)) {
var info = SubscriptionMetaAnnotationsBuildItem.fromJandex(subscription, moduleName);
var info = SubscriptionMetaAnnotationsBuildItem.fromJandex(index.getComputingIndex(), subscription, moduleName);
if (subscription.target().kind() != AnnotationTarget.Kind.METHOD) {
continue;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import io.quarkus.gizmo.MethodDescriptor;
import xyz.block.ftl.Export;
import xyz.block.ftl.Topic;
import xyz.block.ftl.TopicDefinition;
import xyz.block.ftl.runtime.TopicHelper;
import xyz.block.ftl.v1.schema.Decl;

Expand All @@ -30,7 +29,7 @@ public class TopicsProcessor {

@BuildStep
TopicsBuildItem handleTopics(CombinedIndexBuildItem index, BuildProducer<GeneratedClassBuildItem> generatedTopicProducer) {
var topicDefinitions = index.getComputingIndex().getAnnotations(TopicDefinition.class);
var topicDefinitions = index.getComputingIndex().getAnnotations(FTLDotNames.TOPIC_DEFINITION);
log.infof("Processing %d topic definition annotations into decls", topicDefinitions.size());
Map<DotName, TopicsBuildItem.DiscoveredTopic> topics = new HashMap<>();
Set<String> names = new HashSet<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,18 @@

/**
*
* @return The name of the topic to subscribe to.
* @return The name of the topic to subscribe to. Cannot be used in conjunction with {@link #topicClass()}.
*/
String topic();
String topic() default "";

/**
*
* @return The subscription name
*/
String name();

/**
* The class of the topic to subscribe to, which can be used in place of directly specifying the topic name and module.
*/
Class<? extends Topic> topicClass() default Topic.class;
}

0 comments on commit 1a5602f

Please sign in to comment.