-
Notifications
You must be signed in to change notification settings - Fork 406
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
inject-thrift-client: Support Scrooge "service-per-endpoint" function…
…ality Problem Scrooge 4 was just released, and inject-thrift-client has not yet been upgraded. Solution Upgrade inject-thrift-client and create a new FilteredThriftClientModule class. RB_ID=739672
- Loading branch information
Showing
29 changed files
with
882 additions
and
91 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
# Summary | ||
inject-thrift-client is a library for configuring injectable thrift clients. The examples below demonstrate creating a thrift-client for the following thrift defined service: | ||
```thrift | ||
service Greeter { | ||
string hi( | ||
1: string name | ||
) throws (1:InvalidOperation invalidOperation) | ||
ByeResponse bye( | ||
1: string name | ||
2: i32 age | ||
) throws (1:ByeOperation byeOperation) | ||
} | ||
``` | ||
|
||
## FilteredThriftClientModule Usage | ||
FilteredThriftClientModule integrates with Scrooge 4 ["services-per-endpoint"](https://finagle.github.io/blog/2015/09/10/services-per-endpoint-in-scrooge/), supporting per-method filter chains which can retry on requests, successful responses, failed futures, and thrift-idl defined exceptions. | ||
|
||
```scala | ||
object GreeterThriftClientModule | ||
extends FilteredThriftClientModule[Greeter[Future], Greeter.ServiceIface] { | ||
|
||
override val label = "greeter-thrift-client" | ||
override val dest = "flag!greeter-thrift-service" | ||
override val connectTimeout = 1.minute.toDuration | ||
|
||
override def createFilteredClient( | ||
serviceIface: Greeter.ServiceIface, | ||
filterBuilder: FilterBuilder): Greeter[Future] = { | ||
|
||
Thrift.newMethodIface(serviceIface.copy( | ||
hi = filterBuilder.method(Hi) | ||
.timeout(2.minutes) | ||
.constantRetry( | ||
requestTimeout = 1.minute, | ||
shouldRetryResponse = { | ||
case Return(Hi.Result(_, Some(e: InvalidOperation))) => true | ||
case Return(Hi.Result(Some(success), _)) => success == "ERROR" | ||
case Throw(NonFatal(_)) => true | ||
}, | ||
start = 50.millis, | ||
retries = 3) | ||
.filter[HiLoggingThriftClientFilter] | ||
.andThen(serviceIface.hi), | ||
bye = filterBuilder.method(Bye) | ||
.exponentialRetry( | ||
shouldRetryResponse = NonFatalExceptions, | ||
requestTimeout = 1.minute, | ||
start = 50.millis, | ||
multiplier = 2, | ||
retries = 3) | ||
.andThen(serviceIface.bye))) | ||
} | ||
} | ||
``` | ||
|
||
Then add GreeterThriftClientModule to your list of server modules, and inject the "Greeter" thrift-client as such: | ||
```scala | ||
class MyClass @Inject()( | ||
greeter: Greeter[Future]) | ||
``` | ||
|
||
## ThriftClientModule Usage | ||
If you don't need client retries or other client filters, ThriftClientModule can be used to simply create an injectable thrift client as such: | ||
```scala | ||
object GreeterThriftClientModule extends ThriftClientModule[Greeter[Future]] { | ||
override val label = "greeter-thrift-client" | ||
override val dest = "flag!greeter-thrift-service" | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
java_library(name='java', | ||
provides = artifact( | ||
org = 'com.twitter.inject', | ||
name = 'inject-thrift-client-java', | ||
repo = artifactory, | ||
), | ||
dependencies=[ | ||
'3rdparty/jvm/com/google/inject:guice', | ||
], | ||
sources=rglobs('*.java'), | ||
) |
15 changes: 15 additions & 0 deletions
15
inject/inject-thrift-client/src/main/java/com/twitter/inject/thrift/NonFiltered.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package com.twitter.inject.thrift; | ||
|
||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.Target; | ||
|
||
import com.google.inject.BindingAnnotation; | ||
|
||
import static java.lang.annotation.RetentionPolicy.RUNTIME; | ||
|
||
@Retention(RUNTIME) | ||
@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD}) | ||
@BindingAnnotation | ||
public @interface NonFiltered { | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
15 changes: 15 additions & 0 deletions
15
inject/inject-thrift-client/src/main/scala/com/twitter/inject/thrift/FilterBuilder.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package com.twitter.inject.thrift | ||
|
||
import com.twitter.finagle.stats.StatsReceiver | ||
import com.twitter.inject.Injector | ||
import com.twitter.scrooge.ThriftMethod | ||
import javax.inject.Inject | ||
|
||
class FilterBuilder @Inject()( | ||
injector: Injector, | ||
statsReceiver: StatsReceiver) { | ||
|
||
def method(method: ThriftMethod): ThriftClientFilterChain[method.Args, method.Result] = { | ||
new ThriftClientFilterChain[method.Args, method.Result](injector, statsReceiver, method) | ||
} | ||
} |
102 changes: 102 additions & 0 deletions
102
...t-thrift-client/src/main/scala/com/twitter/inject/thrift/FilteredThriftClientModule.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
package com.twitter.inject.thrift | ||
|
||
import com.github.nscala_time.time | ||
import com.google.inject.Provides | ||
import com.twitter.finagle._ | ||
import com.twitter.finagle.factory.TimeoutFactory | ||
import com.twitter.finagle.param.{Label, Stats} | ||
import com.twitter.finagle.service.TimeoutFilter | ||
import com.twitter.finagle.stats.StatsReceiver | ||
import com.twitter.finagle.thrift.{ClientId, ServiceIfaceBuilder} | ||
import com.twitter.inject.TwitterModule | ||
import com.twitter.inject.thrift.FilteredThriftClientModule.MaxDuration | ||
import com.twitter.inject.thrift.conversions.DurationConversions | ||
import com.twitter.scrooge.{ThriftResponse, ThriftService} | ||
import com.twitter.util.{NonFatal, Return, Throw, Try} | ||
import javax.inject.Singleton | ||
import org.joda.time.Duration | ||
import scala.reflect.ClassTag | ||
|
||
object FilteredThriftClientModule { | ||
val MaxDuration = Duration.millis(Long.MaxValue) | ||
} | ||
|
||
abstract class FilteredThriftClientModule[FutureIface <: ThriftService : ClassTag, ServiceIface: ClassTag]( | ||
implicit builder: ServiceIfaceBuilder[ServiceIface]) | ||
extends TwitterModule | ||
with DurationConversions | ||
with time.Implicits { | ||
|
||
/** | ||
* Name of client for use in metrics | ||
*/ | ||
val label: String | ||
|
||
/** | ||
* Destination of client (usually a wily path) | ||
*/ | ||
val dest: String | ||
|
||
/** | ||
* Enable thrift mux for this connection. | ||
* | ||
* Note: Both server and client must have mux enabled otherwise | ||
* a non-descript ChannelClosedException will be seen. | ||
*/ | ||
val mux: Boolean = true | ||
|
||
def requestTimeout: Duration = MaxDuration | ||
|
||
def connectTimeout: Duration = MaxDuration | ||
|
||
def params = { | ||
Stack.Params.empty + | ||
TimeoutFilter.Param(requestTimeout.toTwitterDuration) + | ||
TimeoutFactory.Param(connectTimeout.toTwitterDuration) + | ||
Label(label) | ||
} | ||
|
||
/** | ||
* Add filters to the ServiceIface based client | ||
*/ | ||
def createFilteredClient( | ||
serviceIface: ServiceIface, | ||
filters: FilterBuilder): FutureIface | ||
|
||
@Provides | ||
@Singleton | ||
def providesClient( | ||
@NonFiltered serviceIface: ServiceIface, | ||
filter: FilterBuilder, | ||
statsReceiver: StatsReceiver): FutureIface = { | ||
|
||
createFilteredClient( | ||
serviceIface = serviceIface, | ||
filters = filter) | ||
} | ||
|
||
@Provides | ||
@NonFiltered | ||
@Singleton | ||
def providesUnfilteredServiceIface(clientId: ClientId, statsReceiver: StatsReceiver): ServiceIface = { | ||
val updatedParams = params + | ||
Stats(statsReceiver.scope("clnt")) + | ||
Thrift.param.ClientId(Some(clientId)) | ||
|
||
if (mux) | ||
ThriftMux.client. | ||
withParams(updatedParams). | ||
newServiceIface[ServiceIface](dest) | ||
else | ||
Thrift.client. | ||
withParams(updatedParams). | ||
newServiceIface[ServiceIface](dest) | ||
} | ||
|
||
/* Common Retry Functions */ | ||
|
||
lazy val NonFatalExceptions: PartialFunction[Try[ThriftResponse[_]], Boolean] = { | ||
case Throw(NonFatal(_)) => true | ||
case Return(result) => result.firstException exists NonFatal.isNonFatal | ||
} | ||
} |
Oops, something went wrong.