2016-12-08 8 views
0

В Храбром (zipkin tracer) мы присоединяем состояние, считываемое перехватчиками, путем управления ExecutorService диспетчера.размножающееся состояние, даже если оно не зарегистрировано

как это работает ..

  • прикрепить пролет к теме местного
  • завернуть исполнитель услугу, которые повторно присоединяет срок вызывающего потока к работоспособным
  • сделать диспетчер используй этот исполнитель service

Это работает для синхронных запросов (так как они все равно не используют поток диспетчера) и обычных асинхронных запросов.

Он не работает, когда есть больше соединений в полете, чем разрешено, поскольку асинхронные запросы вставляются в очередь готовности до их выполнения. Очередь готовности не обрабатывается вызывающим потоком запроса, поэтому повторное присоединение не будет работать. Когда перехватчик работает с запросом с задержкой, он не может видеть свой диапазон вызовов, который прерывает трассировку.

Я думал, что, возможно, у приложения-перехватчика может не быть этой проблемы. Если предел хоста/подключения был принудительно (через указанную очередь) на сетевом уровне, я мог бы координировать состояние путем двойного регистрации перехватчика. Этот перехватчик может повторно присоединить состояние, не полагаясь на локаторы потоков, путем сопоставления запросов приложений/сетевых уровней.

К сожалению, это не работает, потому что предел хоста/подключения принудительно (через указанную очередь) на уровне приложения, так что я в тупике.

Я хотел бы отслеживать запросы, особенно если они не загружены. Есть идеи?

Шляпы прочь brianm для обнаружения этой проблемы, кстати

ответ

2

У нас есть внутреннее OkHttpClient обертки, реализующей Call.Factory, который добавляет начальный перехватчик:

public class HttpClient implements Call.Factory { 

private final OkHttpClient ok; 

HttpClient(final OkHttpClient ok) { 
    this.ok = ok; 
} 

/** 
* Implements Call.Factory, uses implicit (thread local) Ctx 
*/ 
public Call newCall(final Request request) { 
    return newCall(Ctx.fromThread().orElseGet(Ctx::empty), request); 
} 


public Call newCall(Ctx ctx, final Request request) { 
    OkHttpClient.Builder b = this.ok.newBuilder(); 
    b.interceptors().add(0, new CtxInterceptor(ctx)); 
    return b.build().newCall(request); 
} 

, чтобы решить эту проблему. Однако это непрозрачно, поэтому для храбрых может быть нехорошо. Он работает нормально, потому что на практике, когда клиент настроен, вы действительно используете интерфейс Call.Factory :-)

бит Ctx бит - это просто контекст с вещами, которые мы хотим размножать, мы можем сделать это неявным или явным, следовательно дополнительный метод, чтобы явно принять его.