use of org.apache.pulsar.common.policies.data.SinkStatus in project pulsar by apache.
the class PulsarGenericObjectSinkTest method testGenericObjectSink.
@Test(groups = { "sink" })
public void testGenericObjectSink() throws Exception {
@Cleanup PulsarClient client = PulsarClient.builder().serviceUrl(container.getPlainTextServiceUrl()).build();
@Cleanup PulsarAdmin admin = PulsarAdmin.builder().serviceHttpUrl(container.getHttpServiceUrl()).build();
// we are not using a parametrized test in order to save resources
// we create one sink that listens on multiple topics, send the records and verify the sink
List<SinkSpec> specs = Arrays.asList(new SinkSpec("test-kv-sink-input-string-" + randomName(8), Schema.STRING, "foo"), new SinkSpec("test-kv-sink-input-avro-" + randomName(8), Schema.AVRO(Pojo.class), Pojo.builder().field1("a").field2(2).build()), new SinkSpec("test-kv-sink-input-json-" + randomName(8), Schema.JSON(Pojo.class), Pojo.builder().field1("a").field2(2).build()), new SinkSpec("test-kv-sink-input-kv-string-int-" + randomName(8), Schema.KeyValue(Schema.STRING, Schema.INT32), new KeyValue<>("foo", 123)), new SinkSpec("test-kv-sink-input-kv-avro-json-inl-" + randomName(8), Schema.KeyValue(Schema.AVRO(PojoKey.class), Schema.JSON(Pojo.class), KeyValueEncodingType.INLINE), new KeyValue<>(PojoKey.builder().field1("a").build(), Pojo.builder().field1("a").field2(2).build())), new SinkSpec("test-kv-sink-input-kv-avro-json-sep-" + randomName(8), Schema.KeyValue(Schema.AVRO(PojoKey.class), Schema.JSON(Pojo.class), KeyValueEncodingType.SEPARATED), new KeyValue<>(PojoKey.builder().field1("a").build(), Pojo.builder().field1("a").field2(2).build())));
final int numRecordsPerTopic = 2;
String sinkName = "genericobject-sink";
String topicNames = specs.stream().map(SinkSpec::getOutputTopicName).collect(Collectors.joining(","));
submitSinkConnector(sinkName, topicNames, "org.apache.pulsar.tests.integration.io.TestGenericObjectSink", JAVAJAR);
// get sink info
getSinkInfoSuccess(sinkName);
getSinkStatus(sinkName);
for (SinkSpec spec : specs) {
@Cleanup Producer<Object> producer = client.newProducer(spec.schema).topic(spec.outputTopicName).create();
for (int i = 0; i < numRecordsPerTopic; i++) {
MessageId messageId = producer.newMessage().value(spec.testValue).property("expectedType", spec.schema.getSchemaInfo().getType().toString()).property("recordNumber", i + "").send();
log.info("sent message {} {} with ID {}", spec.testValue, spec.schema.getSchemaInfo().getType().toString(), messageId);
}
}
try {
log.info("waiting for sink {}", sinkName);
for (int i = 0; i < 120; i++) {
SinkStatus status = admin.sinks().getSinkStatus("public", "default", sinkName);
log.info("sink {} status {}", sinkName, status);
assertEquals(status.getInstances().size(), 1);
SinkStatus.SinkInstanceStatus instance = status.getInstances().get(0);
if (instance.getStatus().numWrittenToSink >= numRecordsPerTopic * specs.size() || instance.getStatus().numSinkExceptions > 0 || instance.getStatus().numSystemExceptions > 0 || instance.getStatus().numRestarts > 0) {
break;
}
Thread.sleep(1000);
}
SinkStatus status = admin.sinks().getSinkStatus("public", "default", sinkName);
log.info("sink {} status {}", sinkName, status);
assertEquals(status.getInstances().size(), 1);
assertTrue(status.getInstances().get(0).getStatus().numWrittenToSink >= numRecordsPerTopic * specs.size());
assertTrue(status.getInstances().get(0).getStatus().numSinkExceptions == 0);
assertTrue(status.getInstances().get(0).getStatus().numSystemExceptions == 0);
log.info("sink {} is okay", sinkName);
} finally {
dumpFunctionLogs(sinkName);
}
deleteSink(sinkName);
getSinkInfoNotFound(sinkName);
}
use of org.apache.pulsar.common.policies.data.SinkStatus in project pulsar by apache.
the class PulsarGenericObjectSinkTest method testGenericObjectSinkWithSchemaChange.
@Test(groups = { "sink" })
public void testGenericObjectSinkWithSchemaChange() throws Exception {
@Cleanup PulsarClient client = PulsarClient.builder().serviceUrl(container.getPlainTextServiceUrl()).build();
@Cleanup PulsarAdmin admin = PulsarAdmin.builder().serviceHttpUrl(container.getHttpServiceUrl()).build();
final int numRecords = 2;
String sinkName = "genericobject-sink";
String topicName = "test-genericobject-sink-schema-change";
submitSinkConnector(sinkName, topicName, "org.apache.pulsar.tests.integration.io.TestGenericObjectSink", JAVAJAR);
// get sink info
getSinkInfoSuccess(sinkName);
getSinkStatus(sinkName);
@Cleanup Producer<byte[]> producer = client.newProducer().topic(topicName).create();
Schema<Pojo> schemav1 = Schema.AVRO(Pojo.class);
Pojo record1 = Pojo.builder().field1("foo").field2(23).build();
producer.newMessage(schemav1).value(record1).property("expectedType", schemav1.getSchemaInfo().getType().toString()).property("expectedSchemaDefinition", schemav1.getSchemaInfo().getSchemaDefinition()).property("recordNumber", "1").send();
Schema<PojoV2> schemav2 = Schema.AVRO(PojoV2.class);
PojoV2 record2 = PojoV2.builder().field1("foo").field2(23).field3(42.5).build();
producer.newMessage(schemav2).value(record2).property("expectedType", schemav2.getSchemaInfo().getType().toString()).property("expectedSchemaDefinition", schemav2.getSchemaInfo().getSchemaDefinition()).property("recordNumber", "2").send();
try {
log.info("waiting for sink {}", sinkName);
for (int i = 0; i < 120; i++) {
SinkStatus status = admin.sinks().getSinkStatus("public", "default", sinkName);
log.info("sink {} status {}", sinkName, status);
assertEquals(status.getInstances().size(), 1);
SinkStatus.SinkInstanceStatus instance = status.getInstances().get(0);
if (instance.getStatus().numWrittenToSink >= numRecords || instance.getStatus().numSinkExceptions > 0 || instance.getStatus().numSystemExceptions > 0 || instance.getStatus().numRestarts > 0) {
break;
}
Thread.sleep(1000);
}
SinkStatus status = admin.sinks().getSinkStatus("public", "default", sinkName);
log.info("sink {} status {}", sinkName, status);
assertEquals(status.getInstances().size(), 1);
assertTrue(status.getInstances().get(0).getStatus().numWrittenToSink >= numRecords);
assertTrue(status.getInstances().get(0).getStatus().numSinkExceptions == 0);
assertTrue(status.getInstances().get(0).getStatus().numSystemExceptions == 0);
log.info("sink {} is okay", sinkName);
} finally {
dumpFunctionLogs(sinkName);
}
deleteSink(sinkName);
getSinkInfoNotFound(sinkName);
}
use of org.apache.pulsar.common.policies.data.SinkStatus in project pulsar by apache.
the class PulsarIOSinkRunner method getSinkStatus.
protected void getSinkStatus(String tenant, String namespace, String sinkName) throws Exception {
final String[] commands = { PulsarCluster.ADMIN_SCRIPT, "sink", "status", "--tenant", tenant, "--namespace", namespace, "--name", sinkName };
final ContainerExecResult result = pulsarCluster.getAnyWorker().execCmd(commands);
log.info("Get sink status : {}", result.getStdout());
assertEquals(result.getExitCode(), 0);
SinkStatus sinkStatus = SinkStatusUtil.decode(result.getStdout());
assertEquals(sinkStatus.getNumInstances(), 1);
assertEquals(sinkStatus.getNumRunning(), 1);
assertEquals(sinkStatus.getInstances().size(), 1);
assertEquals(sinkStatus.getInstances().get(0).getInstanceId(), 0);
assertEquals(sinkStatus.getInstances().get(0).getStatus().isRunning(), true);
assertEquals(sinkStatus.getInstances().get(0).getStatus().getNumRestarts(), 0);
assertEquals(sinkStatus.getInstances().get(0).getStatus().getLatestSystemExceptions().size(), 0);
}
use of org.apache.pulsar.common.policies.data.SinkStatus in project pulsar by apache.
the class SinksImpl method getSinkStatus.
@Override
public SinkStatus getSinkStatus(final String tenant, final String namespace, final String componentName, final URI uri, final String clientRole, final AuthenticationDataSource clientAuthenticationDataHttps) {
// validate parameters
componentStatusRequestValidate(tenant, namespace, componentName, clientRole, clientAuthenticationDataHttps);
SinkStatus sinkStatus;
try {
sinkStatus = new GetSinkStatus().getComponentStatus(tenant, namespace, componentName, uri);
} catch (WebApplicationException we) {
throw we;
} catch (Exception e) {
log.error("{}/{}/{} Got Exception Getting Status", tenant, namespace, componentName, e);
throw new RestException(Response.Status.INTERNAL_SERVER_ERROR, e.getMessage());
}
return sinkStatus;
}
use of org.apache.pulsar.common.policies.data.SinkStatus in project pulsar by yahoo.
the class PulsarSinkE2ETest method testPulsarSinkStats.
private void testPulsarSinkStats(String jarFilePathUrl, Function<SinkConfig, SinkConfig> override) throws Exception {
final String namespacePortion = "io";
final String replNamespace = tenant + "/" + namespacePortion;
final String sourceTopic = "persistent://" + replNamespace + "/input";
final String sinkName = "PulsarSink-test";
final String propertyKey = "key";
final String propertyValue = "value";
final String subscriptionName = "test-sub";
admin.namespaces().createNamespace(replNamespace);
Set<String> clusters = Sets.newHashSet(Lists.newArrayList("use"));
admin.namespaces().setNamespaceReplicationClusters(replNamespace, clusters);
// create a producer that creates a topic at broker
Producer<String> producer = pulsarClient.newProducer(Schema.STRING).topic(sourceTopic).create();
SinkConfig sinkConfig = createSinkConfig(tenant, namespacePortion, sinkName, sourceTopic, subscriptionName);
sinkConfig.setInputSpecs(Collections.singletonMap(sourceTopic, ConsumerConfig.builder().receiverQueueSize(1000).build()));
if (override != null) {
sinkConfig = override.apply(sinkConfig);
}
if (jarFilePathUrl.startsWith(Utils.BUILTIN)) {
sinkConfig.setArchive(jarFilePathUrl);
admin.sinks().createSink(sinkConfig, null);
} else {
admin.sinks().createSinkWithUrl(sinkConfig, jarFilePathUrl);
}
sinkConfig.setInputSpecs(Collections.singletonMap(sourceTopic, ConsumerConfig.builder().receiverQueueSize(523).build()));
if (override != null) {
sinkConfig = override.apply(sinkConfig);
}
if (jarFilePathUrl.startsWith(Utils.BUILTIN)) {
sinkConfig.setArchive(jarFilePathUrl);
admin.sinks().updateSink(sinkConfig, null);
} else {
admin.sinks().updateSinkWithUrl(sinkConfig, jarFilePathUrl);
}
retryStrategically((test) -> {
try {
TopicStats topicStats = admin.topics().getStats(sourceTopic);
return topicStats.getSubscriptions().containsKey(subscriptionName) && topicStats.getSubscriptions().get(subscriptionName).getConsumers().size() == 1 && topicStats.getSubscriptions().get(subscriptionName).getConsumers().get(0).getAvailablePermits() == 523;
} catch (PulsarAdminException e) {
return false;
}
}, 50, 150);
TopicStats topicStats = admin.topics().getStats(sourceTopic);
assertEquals(topicStats.getSubscriptions().size(), 1);
assertTrue(topicStats.getSubscriptions().containsKey(subscriptionName));
assertEquals(topicStats.getSubscriptions().get(subscriptionName).getConsumers().size(), 1);
assertEquals(topicStats.getSubscriptions().get(subscriptionName).getConsumers().get(0).getAvailablePermits(), 523);
// make sure there are no errors in the sink
SinkStatus status = admin.sinks().getSinkStatus(tenant, namespacePortion, sinkName);
status.getInstances().forEach(sinkInstanceStatus -> assertEquals(sinkInstanceStatus.status.numSinkExceptions, 0));
status.getInstances().forEach(sinkInstanceStatus -> assertEquals(sinkInstanceStatus.status.numSystemExceptions, 0));
// validate prometheus metrics empty
String prometheusMetrics = PulsarFunctionTestUtils.getPrometheusMetrics(pulsar.getListenPortHTTP().get());
log.info("prometheus metrics: {}", prometheusMetrics);
Map<String, PulsarFunctionTestUtils.Metric> metrics = PulsarFunctionTestUtils.parseMetrics(prometheusMetrics);
PulsarFunctionTestUtils.Metric m = metrics.get("pulsar_sink_received_total");
assertEquals(m.tags.get("cluster"), config.getClusterName());
assertEquals(m.tags.get("instance_id"), "0");
assertEquals(m.tags.get("name"), sinkName);
assertEquals(m.tags.get("namespace"), String.format("%s/%s", tenant, namespacePortion));
assertEquals(m.tags.get("fqfn"), FunctionCommon.getFullyQualifiedName(tenant, namespacePortion, sinkName));
assertEquals(m.value, 0.0);
m = metrics.get("pulsar_sink_received_total_1min");
assertEquals(m.tags.get("cluster"), config.getClusterName());
assertEquals(m.tags.get("instance_id"), "0");
assertEquals(m.tags.get("name"), sinkName);
assertEquals(m.tags.get("namespace"), String.format("%s/%s", tenant, namespacePortion));
assertEquals(m.tags.get("fqfn"), FunctionCommon.getFullyQualifiedName(tenant, namespacePortion, sinkName));
assertEquals(m.value, 0.0);
m = metrics.get("pulsar_sink_written_total");
assertEquals(m.tags.get("cluster"), config.getClusterName());
assertEquals(m.tags.get("instance_id"), "0");
assertEquals(m.tags.get("name"), sinkName);
assertEquals(m.tags.get("namespace"), String.format("%s/%s", tenant, namespacePortion));
assertEquals(m.tags.get("fqfn"), FunctionCommon.getFullyQualifiedName(tenant, namespacePortion, sinkName));
assertEquals(m.value, 0.0);
m = metrics.get("pulsar_sink_written_total_1min");
assertEquals(m.tags.get("cluster"), config.getClusterName());
assertEquals(m.tags.get("instance_id"), "0");
assertEquals(m.tags.get("name"), sinkName);
assertEquals(m.tags.get("namespace"), String.format("%s/%s", tenant, namespacePortion));
assertEquals(m.tags.get("fqfn"), FunctionCommon.getFullyQualifiedName(tenant, namespacePortion, sinkName));
assertEquals(m.value, 0.0);
m = metrics.get("pulsar_sink_sink_exceptions_total");
assertEquals(m.tags.get("cluster"), config.getClusterName());
assertEquals(m.tags.get("instance_id"), "0");
assertEquals(m.tags.get("name"), sinkName);
assertEquals(m.tags.get("namespace"), String.format("%s/%s", tenant, namespacePortion));
assertEquals(m.tags.get("fqfn"), FunctionCommon.getFullyQualifiedName(tenant, namespacePortion, sinkName));
assertEquals(m.value, 0.0);
m = metrics.get("pulsar_sink_sink_exceptions_total_1min");
assertEquals(m.tags.get("cluster"), config.getClusterName());
assertEquals(m.tags.get("instance_id"), "0");
assertEquals(m.tags.get("name"), sinkName);
assertEquals(m.tags.get("namespace"), String.format("%s/%s", tenant, namespacePortion));
assertEquals(m.tags.get("fqfn"), FunctionCommon.getFullyQualifiedName(tenant, namespacePortion, sinkName));
assertEquals(m.value, 0.0);
m = metrics.get("pulsar_sink_system_exceptions_total");
assertEquals(m.tags.get("cluster"), config.getClusterName());
assertEquals(m.tags.get("instance_id"), "0");
assertEquals(m.tags.get("name"), sinkName);
assertEquals(m.tags.get("namespace"), String.format("%s/%s", tenant, namespacePortion));
assertEquals(m.tags.get("fqfn"), FunctionCommon.getFullyQualifiedName(tenant, namespacePortion, sinkName));
assertEquals(m.value, 0.0);
m = metrics.get("pulsar_sink_system_exceptions_total_1min");
assertEquals(m.tags.get("cluster"), config.getClusterName());
assertEquals(m.tags.get("instance_id"), "0");
assertEquals(m.tags.get("name"), sinkName);
assertEquals(m.tags.get("namespace"), String.format("%s/%s", tenant, namespacePortion));
assertEquals(m.tags.get("fqfn"), FunctionCommon.getFullyQualifiedName(tenant, namespacePortion, sinkName));
assertEquals(m.value, 0.0);
m = metrics.get("pulsar_sink_last_invocation");
assertEquals(m.tags.get("cluster"), config.getClusterName());
assertEquals(m.tags.get("instance_id"), "0");
assertEquals(m.tags.get("name"), sinkName);
assertEquals(m.tags.get("namespace"), String.format("%s/%s", tenant, namespacePortion));
assertEquals(m.tags.get("fqfn"), FunctionCommon.getFullyQualifiedName(tenant, namespacePortion, sinkName));
assertEquals(m.value, 0.0);
int totalMsgs = 10;
for (int i = 0; i < totalMsgs; i++) {
String data = "my-message-" + i;
producer.newMessage().property(propertyKey, propertyValue).value(data).send();
}
retryStrategically((test) -> {
try {
SubscriptionStats subStats = admin.topics().getStats(sourceTopic).getSubscriptions().get(subscriptionName);
return subStats.getUnackedMessages() == 0 && subStats.getMsgOutCounter() == totalMsgs;
} catch (PulsarAdminException e) {
return false;
}
}, 5, 200);
SubscriptionStats subStats = admin.topics().getStats(sourceTopic).getSubscriptions().get(subscriptionName);
assertEquals(subStats.getUnackedMessages(), 0);
assertEquals(subStats.getMsgOutCounter(), totalMsgs);
assertEquals(subStats.getMsgBacklog(), 0);
// make sure there are no errors in the sink after producing
status = admin.sinks().getSinkStatus(tenant, namespacePortion, sinkName);
status.getInstances().forEach(sinkInstanceStatus -> assertEquals(sinkInstanceStatus.status.numSinkExceptions, 0));
status.getInstances().forEach(sinkInstanceStatus -> assertEquals(sinkInstanceStatus.status.numSystemExceptions, 0));
// get stats after producing
prometheusMetrics = PulsarFunctionTestUtils.getPrometheusMetrics(pulsar.getListenPortHTTP().get());
log.info("prometheusMetrics: {}", prometheusMetrics);
metrics = PulsarFunctionTestUtils.parseMetrics(prometheusMetrics);
m = metrics.get("pulsar_sink_received_total");
assertEquals(m.tags.get("cluster"), config.getClusterName());
assertEquals(m.tags.get("instance_id"), "0");
assertEquals(m.tags.get("name"), sinkName);
assertEquals(m.tags.get("namespace"), String.format("%s/%s", tenant, namespacePortion));
assertEquals(m.tags.get("fqfn"), FunctionCommon.getFullyQualifiedName(tenant, namespacePortion, sinkName));
assertEquals(m.value, (double) totalMsgs);
m = metrics.get("pulsar_sink_received_total_1min");
assertEquals(m.tags.get("cluster"), config.getClusterName());
assertEquals(m.tags.get("instance_id"), "0");
assertEquals(m.tags.get("name"), sinkName);
assertEquals(m.tags.get("namespace"), String.format("%s/%s", tenant, namespacePortion));
assertEquals(m.tags.get("fqfn"), FunctionCommon.getFullyQualifiedName(tenant, namespacePortion, sinkName));
assertEquals(m.value, (double) totalMsgs);
m = metrics.get("pulsar_sink_written_total");
assertEquals(m.tags.get("cluster"), config.getClusterName());
assertEquals(m.tags.get("instance_id"), "0");
assertEquals(m.tags.get("name"), sinkName);
assertEquals(m.tags.get("namespace"), String.format("%s/%s", tenant, namespacePortion));
assertEquals(m.tags.get("fqfn"), FunctionCommon.getFullyQualifiedName(tenant, namespacePortion, sinkName));
assertEquals(m.value, (double) totalMsgs);
m = metrics.get("pulsar_sink_written_total_1min");
assertEquals(m.tags.get("cluster"), config.getClusterName());
assertEquals(m.tags.get("instance_id"), "0");
assertEquals(m.tags.get("name"), sinkName);
assertEquals(m.tags.get("namespace"), String.format("%s/%s", tenant, namespacePortion));
assertEquals(m.tags.get("fqfn"), FunctionCommon.getFullyQualifiedName(tenant, namespacePortion, sinkName));
assertEquals(m.value, (double) totalMsgs);
m = metrics.get("pulsar_sink_sink_exceptions_total");
assertEquals(m.tags.get("cluster"), config.getClusterName());
assertEquals(m.tags.get("instance_id"), "0");
assertEquals(m.tags.get("name"), sinkName);
assertEquals(m.tags.get("namespace"), String.format("%s/%s", tenant, namespacePortion));
assertEquals(m.tags.get("fqfn"), FunctionCommon.getFullyQualifiedName(tenant, namespacePortion, sinkName));
assertEquals(m.value, 0.0);
m = metrics.get("pulsar_sink_sink_exceptions_total_1min");
assertEquals(m.tags.get("cluster"), config.getClusterName());
assertEquals(m.tags.get("instance_id"), "0");
assertEquals(m.tags.get("name"), sinkName);
assertEquals(m.tags.get("namespace"), String.format("%s/%s", tenant, namespacePortion));
assertEquals(m.tags.get("fqfn"), FunctionCommon.getFullyQualifiedName(tenant, namespacePortion, sinkName));
assertEquals(m.value, 0.0);
m = metrics.get("pulsar_sink_system_exceptions_total");
assertEquals(m.tags.get("cluster"), config.getClusterName());
assertEquals(m.tags.get("instance_id"), "0");
assertEquals(m.tags.get("name"), sinkName);
assertEquals(m.tags.get("namespace"), String.format("%s/%s", tenant, namespacePortion));
assertEquals(m.tags.get("fqfn"), FunctionCommon.getFullyQualifiedName(tenant, namespacePortion, sinkName));
assertEquals(m.value, 0.0);
m = metrics.get("pulsar_sink_system_exceptions_total_1min");
assertEquals(m.tags.get("cluster"), config.getClusterName());
assertEquals(m.tags.get("instance_id"), "0");
assertEquals(m.tags.get("name"), sinkName);
assertEquals(m.tags.get("namespace"), String.format("%s/%s", tenant, namespacePortion));
assertEquals(m.tags.get("fqfn"), FunctionCommon.getFullyQualifiedName(tenant, namespacePortion, sinkName));
assertEquals(m.value, 0.0);
m = metrics.get("pulsar_sink_last_invocation");
assertEquals(m.tags.get("cluster"), config.getClusterName());
assertEquals(m.tags.get("instance_id"), "0");
assertEquals(m.tags.get("name"), sinkName);
assertEquals(m.tags.get("namespace"), String.format("%s/%s", tenant, namespacePortion));
assertEquals(m.tags.get("fqfn"), FunctionCommon.getFullyQualifiedName(tenant, namespacePortion, sinkName));
assertTrue(m.value > 0.0);
// delete functions
admin.sinks().deleteSink(tenant, namespacePortion, sinkName);
retryStrategically((test) -> {
try {
return admin.topics().getStats(sourceTopic).getSubscriptions().size() == 0;
} catch (PulsarAdminException e) {
return false;
}
}, 50, 150);
// make sure subscriptions are cleanup
assertEquals(admin.topics().getStats(sourceTopic).getSubscriptions().size(), 0);
tempDirectory.assertThatFunctionDownloadTempFilesHaveBeenDeleted();
}
Aggregations