How can I configure retry configuration in javaoperatorsdk - fabric8

We are using io.javaoperatorsdk version 2.1.4 to create kubernates operator
How can we configure retry configuration. I went through the doc but didnot understand the way how to configure. could some one help on this ?
I have code like below
#ControllerConfiguration
public class ApplicationsReconciler implements Reconciler<AppCustomResource>,
ErrorStatusHandler<AppCustomResource>,
EventSourceInitializer<AppCustomResource> {
....
.....
}
KubernetesClient client = new DefaultKubernetesClient(config);
Operator operator = new Operator(client,
ApmOperatorConfigurationServiceOverrider.getService());
operator.register(new ApplicationsReconciler(client));

Related

Cannot connect to redis using spring and lettuce

I am struggling to find what could be wring here; need help.
I am using spring-data-redis 2.4.1
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration()
redisStandaloneConfiguration.setHostname(hostname)
redisStandaloneConfiguration.setPort(6379)
redisStandaloneConfiguration.setPassword("password")
I then create lettuceClientConfigurationBuilder and specify clientName
I then use lettuceClientConfiguration and redisStandaloneConfiguration to create ClientConnectionFactory.
However, when we call getConnection() on the connection Factory, we get
WrongPass Invalid username-password pair
The same set of username-password works with Redis-CLI on cmd prompt.
Is there is something wrong in the way I am using in my java application?
Any pointer/hint towards solving this would be greatly appreciated.
Spring Boot configures LettuceConnectionFactory for you, you can specify the connection params on the application.properties file.
spring.redis.database=0
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=yourPassword
spring.redis.timeout=60000
If you wanna do it programmatically, set the spring.redis.password in application.properties and try this:
#Configuration
class AppConfig {
#Bean
public LettuceConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(new RedisStandaloneConfiguration("server", 6379));
}
}
I had mistaken username for clientname set on LettuceClientConfigurationBuilder but username had to be specified on the redisstandaloneconfiguratuon.
This works for me; also please note acl was introduced only after lettuce 2.4.1 so any prior version will not work.
redisStandaloneConfiguration.setUsername(connectionFactoryConfigs.getUserName());

Spring sleuth Baggage key not getting propagated

I've a filter (OncePerRequestFilter) which basically intercepts incoming request and logs traceId, spanId etc. which works well,
this filter lies in a common module which is included in other projects to avoid including spring sleuth dependency in all of my micro-services, the reason why I've created it as a library because any changes to library will be common to all modules.
Now I've to add a new propagation key which need to be propagated to all services via http headers like trace and spanId for that I've extracted current span from HttpTracing and added a baggage key to it (as shown below)
Span span = httpTracing.tracing().tracer().currentSpan();
String corelationId =
StringUtils.isEmpty(request.getHeader(CORELATION_ID))
? "n/a"
: request.getHeader(CORELATION_ID);
ExtraFieldPropagation.set(CUSTOM_TRACE_ID_MDC_KEY_NAME, corelationId);
span.annotate("baggage_set");
span.tag(CUSTOM_TRACE_ID_MDC_KEY_NAME, corelationId);
I've added propagation-keys and whitelisted-mdc-keys to my application.yml (with my library) file like below
spring:
sleuth:
propagation-keys:
- x-corelationId
log:
slf4j:
whitelisted-mdc-keys:
- x-corelationId
After making this change in filter the corelationId is not available when I make a http call to another service with same app, basically keys are not getting propagated.
In your library you can implement ApplicationEnvironmentPreparedEvent listener and add the configuration you need there
Ex:
#Component
public class CustomApplicationListener implements ApplicationListener<ApplicationEvent> {
private static final Logger log = LoggerFactory.getLogger(LagortaApplicationListener.class);
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationEnvironmentPreparedEvent) {
log.debug("Custom ApplicationEnvironmentPreparedEvent Listener");
ApplicationEnvironmentPreparedEvent envEvent = (ApplicationEnvironmentPreparedEvent) event;
ConfigurableEnvironment env = envEvent.getEnvironment();
Properties props = new Properties();
props.put("spring.sleuth.propagation-keys", "x-corelationId");
props.put("log.slf4j.whitelisted-mdc-keys:", "x-corelationId");
env.getPropertySources().addFirst(new PropertiesPropertySource("custom", props));
}
}
}
Then in your microservice you will register this custom listener
public static void main(String[] args) {
ConfigurableApplicationContext context = new SpringApplicationBuilder(MyApplication.class)
.listeners(new CustomApplicationListener()).run();
}
I've gone through documentation and seems like I need to add spring.sleuth.propagation-keys and whitelist them by using spring.sleuth.log.slf4j.whitelisted-mdc-keys
Yes you need to do this
is there another way to add these properties in common module so that I do not need to include them in each and every micro services.
Yes, you can use Spring Cloud Config server and a properties file called application.yml / application.properties that would set those properties for all microservices
The answer from Mahmoud works great when you want register the whitelisted-mdc-keys programatically.
An extra tip when you need these properties also in a test, then you can find the anwser in this post: How to register a ApplicationEnvironmentPreparedEvent in Spring Test

Set heartbeatintervalseconds using spring xml

I am using spring-data-Cassandra v1.3.2 in my project.
Is it possible to set heartbeatintervalseconds using spring configuration XML file.
Getting 4 lines of hearbeat DEBUG logs every 30 seconds in my application logs and i am not sure how to avoid them.
Unfortunately, no.
After reviewing the SD Cassandra CassandraCqlClusterParser class, it is apparent that you can specify both "local" and "remote" connection pooling options, however, neither handler handles all the Cassandra Java driver "pooling options" appropriately (such as heartbeatIntervalSeconds).
It appears several other options are missing as well: idleTimeoutSeconds, initializationExecutor, poolTimeoutMillis, and protocolVersion.
Equally unfortunate is it appears the SD Cassandra PoolOptionsFactoryBean does not support these "pooling options" either.
However, not all is lost.
While your SD Cassandra application may resolve it's configuration primarily from XML, it does not preclude you from using a combination of Java config and XML.
For instance, you could use a Spring Java config class to configure your cluster and express your PoolingOptions in Java config...
#Configuration
#ImportResource("/class/path/to/cassandra/config.xml")
class CassandraConfig {
#Bean
PoolingOptions poolingOptions() {
PoolingOptions poolingOptions = new PoolingOptions();
poolingOptions.setHeartbeatIntervalSeconds(30);
poolingOptions.setIdleTimeoutSeconds(300);
poolingOptions.setMaxConnectionsPerHost(50);
poolingOptions.set...
return poolingOptions;
}
#Bean
CassandraClusterFactoryBean cluster() {
CassandraClusterFactoryBean cluster = new CassandraClusterFactoryBean()
cluster.setContactPoints("..");
cluster.setPort(1234);
cluster.setPoolingOptions(poolingOptions());
cluster.set...
return cluster;
}
}
Hope this helps.
As an FYI, you may want to upgrade to the "current" Spring Data Cassandra version, 1.4.1.RELEASE.
Sadly, but the answer is no. It's not possible to configure the heartbeat interval using XML configuration. Only the following local/remote properties can be configured in PoolingOptions:
min-simultaneous-requests
max-simultaneous-requests
core-connections
max-connections
If you switch to Java-based configuration, then you're able to configure PoolingOptions by extending AbstractClusterConfiguration:
#Configuration
public class MyConfig extends AbstractClusterConfiguration {
#Override
protected PoolingOptions getPoolingOptions() {
PoolingOptions poolingOptions = new PoolingOptions();
poolingOptions.setHeartbeatIntervalSeconds(10);
return poolingOptions
}
}

Camel: use datasource configured by spring-boot

I have a project and in it I'm using spring-boot-jdbc-starter and it automatically configures a DataSource for me.
Now I added camel-spring-boot to project and I was able to successfully create routes from Beans of type RouteBuilder.
But when I'm using sql component of camel it can not find datasource. Is there any simple way to add Spring configured datasource to CamelContext? In samples of camel project they use spring xml for datasource configuration but I'm looking for a way with java config. This is what I tried:
#Configuration
public class SqlRouteBuilder extends RouteBuilder {
#Bean
public SqlComponent sqlComponent(DataSource dataSource) {
SqlComponent sqlComponent = new SqlComponent();
sqlComponent.setDataSource(dataSource);
return sqlComponent;
}
#Override
public void configure() throws Exception {
from("sql:SELECT * FROM tasks WHERE STATUS NOT LIKE 'completed'")
.to("mock:sql");
}
}
I have to publish it because although the answer is in the commentary, you may not notice it, and in my case such a configuration was necessary to run the process.
The use of the SQL component should look like this:
from("timer://dbQueryTimer?period=10s")
.routeId("DATABASE_QUERY_TIMER_ROUTE")
.to("sql:SELECT * FROM event_queue?dataSource=#dataSource")
.process(xchg -> {
List<Map<String, Object>> row = xchg.getIn().getBody(List.class);
row.stream()
.map((x) -> {
EventQueue eventQueue = new EventQueue();
eventQueue.setId((Long)x.get("id"));
eventQueue.setData((String)x.get("data"));
return eventQueue;
}).collect(Collectors.toList());
})
.log(LoggingLevel.INFO,"******Database query executed - body:${body}******");
Note the use of ?dataSource=#dataSource. The dataSource name points to the DataSource object configured by Spring, it can be changed to another one and thus use different DataSource in different routes.
Here is the sample/example code (Java DSL). For this I used
Spring boot
H2 embedded Database
Camel
on startup spring-boot, creates table and loads data. Then camel route, runs "select" to pull the data.
Here is the code:
public void configure() throws Exception {
from("timer://timer1?period=1000")
.setBody(constant("select * from Employee"))
.to("jdbc:dataSource")
.split().simple("${body}")
.log("process row ${body}")
full example in github

Using Jackson as Jersey client serializer

Is it possible to use Jackson as the serializer/marshaller for JSON data instead of JAXB when using Jersey Client API?
If so how to configure it?
OK, I found it out, it turns out to be quite simple after all:
ClientConfig cc = new DefaultClientConfig();
cc.getClasses().add(JacksonJsonProvider.class);
Client clientWithJacksonSerializer = Client.create(cc);
The JacksonJsonProvider comes from the jackson-jaxrs package.
You may skip the creation of external config and register the provider directly:
Client client = ClientBuilder.newClient().register(JacksonJsonProvider.class)
Solution with JacksonJaxbJsonProvider
Common way how to use Jackson with custom configuration in Jersey client was to use JacksonJaxbJsonProvider for example like this
JacksonJaxbJsonProvider provider = new JacksonJaxbJsonProvider();
provider.setMapper(yourObjectMapper());
Client client = ClientBuilder.newClient(new ClientConfig(provider));
Unfortunately in Jersey 2.26 they copied JacksonJaxbJsonProvider class
from com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider artifact (Jackson)
to org.glassfish.jersey.media:jersey-media-json-jackson artifact (Jersey)
and changed package
from com.fasterxml.jackson.jaxrs.json
to org.glassfish.jersey.jackson.internal.jackson.jaxrs.json.
It is still possible to use this approach it's just needed to change JacksonJaxbJsonProvider import.
Apart from JacksonJaxbJsonProvider being now in internal package drawback is also
that you must know on which Jersey version your code runs which might be a problem when different dependencies require different Jersey versions.
Better solution with ContextResolver<ObjectMapper>
Better possibility how to configure Jackson in Jersey client is to use the same way how it is configured in Jersey server which is to create ObjectMapper provider like this:
#Provider
#Produces(MediaType.APPLICATION_JSON)
public class ObjectMapperProvider implements ContextResolver<ObjectMapper> {
private ObjectMapper objectMapper = yourObjectMapper();
#Override
public ObjectMapper getContext(Class<?> objectType) {
return objectMapper;
}
}
and use it for example like this:
ClientConfig clientConfig = new ClientConfig();
clientConfig.register(JacksonFeature.class); // usually auto-discovered
clientConfig.register(new ObjectMapperProvider());
Client client = ClientBuilder.newClient(clientConfig);
If you have both the server and the client you can reuse ObjectMapperProvider class.
It seems that this approach works from Jersey version 2.9.
You might also want to try org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider (jackson-jaxrs 1.6.1).
I ran into similar issue, but for me none of the suggestions given here worked.
What worked for me was below piece of code:
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Client;
...
ClientBuilder clientBuilder = ClientBuilder.newBuilder()
clientBuilder.register(JacksonFeature.class);
...
Client client = clientBuilder.build();
The key change was usage of JacksonFeature.class - it comes from jersey-media-json-jackson-x.yy.jar
I got clue to use this solution from this article - http://www.baeldung.com/jersey-jax-rs-client
For jersey 2.22.2 and Jackson 2.7.2 gradle dependencies are:
dependencies {
compile("com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:2.7.2")
compile("org.glassfish.jersey.core:jersey-client:2.22.2")
}
Sample client code is:
final String name = "world";
final Client client = ClientBuilder.newClient().register(JacksonJaxbJsonProvider.class);
final WebTarget target = client.target("http://localhost:8080").path("hello").path(name);
final Message message = target.request().get(Message.class);
System.out.println(message.getWelcomeMessage()); // hello world

Resources