Trace Id not preserved when calling netflix FeignClient - netflix-feign

I am using spring-cloud-sleuth-zipkin and spring-cloud-starter-sleuth as dependency.
When i call a netflix FeignClient call TraceId changes...
import org.springframework.cloud.netflix.feign.FeignClient;
#FeignClient
public interface TesterClient {
#RequestLine("GET /testCall")
#Headers({"Authorization: Bearer {bearerToken}",
"Content-Type: application/json"})
ResponseEntity<Test> testMethod(#Param("bearerToken") String bearerToken);
}
#Bean
public TesterClient testerClient() {
return Feign.builder()
.decoder(new TestDecoder()).encoder(new TestEncoder())
.logLevel(Logger.Level.FULL).target(TesterClient.class,
this.testUrl);
}
When i call TesterClient the traceId changes? How could i preserve the same traceId?

Related

Can we apply custom WebContentTypeMapper only to a particular WCF call?

I have a WCF service that accepts only requests of Content-Type=application/json. I want my service to accept text/plain request only for a particular OperationContract. I can use a custom WebContentTypeMapper to make the service to treat text/plain requests as application/json but I don't know how to scope it to only a particular OperationContract.
Sample stub -
public class MyService
{
[OperationContract]
public string Foo(string arg1, string arg2)
{
//Do something
}
[OperationContract]
public string Bar(string arg1, string arg2)
{
//Do something else
}
}
public class JsonContentTypeMapper : WebContentTypeMapper
{
public override WebContentFormat GetMessageFormatForContentType(string contentType)
{
if( contentType.ToLowerInvariant() == "text/plain;charset=utf-8" )
{
// The check below fails because for each request this function is called twice.
// The HttpContext is set the first time and its empty the second time.
if( HttpContext.Current.Request.Path.EndsWith("Foo") )
{
return WebContentFormat.Json;
}
return WebContentFormat.Default;
}
}
}
Context: During app closing I'm sending a sendBeacon request to my service to do cleanup. sendBeacon requests cannot have content-type=application/json. I can't use sync-xhr because it is being deprecated in Chrome and are a blocking call and hang navigation to next page. I can't use async-xhr because this request will be called in unload event during which the browsers ignore async-xhr requests.

same HttpPut request code format not working but the works on another request

I have a HTTPPUT request that is not being called. I have a similar put request that manages another tab and it works. Both pages are pretty identical. I don't know what I am doing wrong.
I have tried almost everything and don't know what else to try.
controller:
[HttpPut]
[Route("updateAllocations({type})")]
public IHttpActionResult UpdateAllocations(string type, T_LOC entity)
{
System.Diagnostics.Debug.WriteLine("inside");
_allocationsService.UpdateAllocations(type,entity);
return Ok();
}
interface:
using OTPS.Core.Objects;
using System.Collections.Generic;
using OTPS.Core.Models;
namespace OTPS.Core.Interfaces
{
public interface IAllocationsService
{
void UpdateAllocations(string type, T_LOC entity);
}
}
service:
public void UpdateAllocations(string type, T_LOC entity)
{
System.Diagnostics.Debug.WriteLine("inside");
}
CLIENT SIDE:
public updateAllocation(type: string , entity) {
console.log("sdfsdf")
console.log(`${this.baseUrl}/api/allocations/updateAllocations(${type})`)
return this.http.put(`${this.baseUrl}/api/allocations/updateAllocations({type})`, entity, { headers: this.headers, withCredentials: true })
.pipe(catchError((error: Error) => {
console.log("sdfasd111111sdf")
return this.errorService.handleError(error);
}));
}
I am expecting the clinet side to call the put request before making any further logic but the print on server side never gets called..
Make sure that you subscribe to the service method inside component:
this.myService.updateAllocation(type, entity).subscribe( response => {
// do something here with response
});
You must call subscribe() or nothing happens. Just calling
Service method does not initiate the PUT/DELETE/POST/GET request.
Always subscribe!
An HttpClient method does not begin its HTTP request until you call
subscribe() on the observable returned by that method. This is true
for all HttpClient methods.

Spring cloud stream - Autowiring underlying Consumer for a given PollableMessageSource

Is it possible to get a hold of underlying KafkaConsumer bean for a defined PollableMessageSource?
I have Binding defined as:
public interface TestBindings {
String TEST_SOURCE = "test";
#Input(TEST_SOURCE)
PollableMessageSource testTopic();
}
and config class:
#EnableBinding(TestBindings.class)
public class TestBindingsPoller {
#Bean
public ApplicationRunner testPoller(PollableMessageSource testTopic) {
// Get kafka consumer for PollableMessageSource
KafkaConsumer kafkaConsumer = getConsumer(testTopic);
return args -> {
while (true) {
if (!testTopic.poll(...) {
Thread.sleep(500);
}
}
};
}
}
The question is, how can I get KafkaConsumer that corresponds to testTopic? Is there any way to get it from beans that are wired in spring cloud stream?
The KafkaMessageSource populates a KafkaConsumer into headers, so it is available in the place you receive messages: https://github.com/spring-projects/spring-kafka/blob/master/spring-kafka/src/main/java/org/springframework/kafka/support/converter/MessageConverter.java#L57.
If you are going to do stuff like poll yourself, I would suggest to inject a ConsumerFactory and use a consumer from there already.

CompletableFuture: control http response status-codes

I'm currently struggeling returning http response status-codes on certain conditions. Let's say, the return objetct of taskService.getNewTasks is null. In this case I want to return status-code 404. On some exception I want to return some 50x, and so on.
My code so far
#RestController
public class TaskController {
#Autowired
private TaskService taskService;
#GetMapping(path = "gettasks")
private Future<Tasks> getNewTasks() {
return taskService.getNewTasks();
}
...
}
#Service
public class TaskService {
#Async
public Future<Tasks> getNewTasks() {
...
return CompletableFuture.completedFuture(tasks);
}
}
This could suit you.
#GetMapping(path = "gettasks")
private CompletableFuture<ResponseEntity<Tasks>> getNewTasks() {
CompletableFuture<Tasks> future = new CompletableFuture<>();
future.complete(taskService.getNewTasks());
if(yourCondition){
return future.thenApply(result -> new ResponseEntity<Tasks>(result, HttpStatus.STATUS_1));
}
return future.thenApply(result -> new ResponseEntity<Tasks>(result, HttpStatus.STATUS_2));
}
As described in https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-ann-return-types, Future isn’t supported as return type for controller handler methods.
Since you’re using CompletableFuture you can just return that or CompletionStage, which are supported by spring.
If that completes with an exception, you can use the regular Spring exception handling mechanisms like annotating the exception with #ResponseStatus .

Return raw strings from #SubscribeMapping with STOMP/WebSockets/Spring

I've got a Spring-MVC controller using STOMP over websockets. Everything works fine apart from the String received in my STOMP JavaScript client upon subscription has been escaped, presumably by Spring.
All the examples I can find on the web and in official documentation uses POJOs for the return types and then uses Jackson JSON conversion auto-magically - I do not want this as the JSON I return is entirely dynamic - how do I switch this nonsense off so I can just return a plain string!?
#Controller
public class FooController {
#SubscribeMapping("/foo")
public String getUser() {
String json = customJsonConversion();
return json;
}
JSON received looks is in this form "{\"x\":1}" if output of customJsonConversion is {"x":1}
Looks like you want to disable Jackson conversion. It is registered by default AbstractMessageBrokerConfiguration#brokerMessageConverter():
if (registerDefaults) {
if (jackson2Present) {
DefaultContentTypeResolver resolver = new DefaultContentTypeResolver();
resolver.setDefaultMimeType(MimeTypeUtils.APPLICATION_JSON);
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
converter.setContentTypeResolver(resolver);
converters.add(converter);
}
converters.add(new StringMessageConverter());
converters.add(new ByteArrayMessageConverter());
}
To disable that you should do this in your custom WebSocketMessageBrokerConfigurer:
public boolean configureMessageConverters(List<MessageConverter> messageConverters) {
messageConverters.add(new StringMessageConverter());
messageConverters.add(new ByteArrayMessageConverter());
return false;
}

Resources