Sitelet https://github.com/twitter/scrooge/commit/3fbb635936d82c00456b332647ea9136841f3227
Skip to content

Commit 3fbb635

Browse files
committed
scrooge: Generate a finagle Service per thrift method
Problem Scrooge-generated services are not finagle Services, so they do not allow using Filters. Solution Generate a wrapper service that delegates to the underlying thrift service. Result For a thrift service, e.g. service Logger { string log(1: string message, 2: i32 logLevel); i32 getLogSize(); } Scrooge generates: class Logger$ServiceImpl(underlying: Logger[Future]) { val log: com.twitter.finagle.Service[(String, Int), String] = ... val getLogSize: com.twitter.finagle.Service[Unit, Int] = ... } Usage in finagle: val client = ThriftMux.newServiceIface(Logger, "localhost:8080") client.log(Logger.Log.Args("message", 1)) onSuccess {...} This avoids the reflection-based initialization (ThriftRichClient) by collecting the relevant types during generation. Compatibility constructor to build a FutureIface from a ServiceIface: val loggerFutureIface = Logger.newFutureIface(loggerServiceIface) loggerFutureIface.log("msg") Client configuration is done by e.g. ThriftMux.client.withClientId(ClientId("asdf")).newServiceIface(Logger, dest) RB_ID=663690
1 parent 8554aa1 commit 3fbb635

27 files changed

Lines changed: 663 additions & 316 deletions

‎CHANGES‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ as it is included in Scrooge's user's guide.
55
3.x
66
~~~~~~~
77

8+
- scrooge: Generate a finagle Service per thrift method (Service interface)
9+
810
3.19.0
911
~~~~~~~
1012
- scrooge: Performance improvements and bug fixes.

‎scrooge-core/src/main/scala/com/twitter/scrooge/ThriftStruct.scala‎

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,22 @@ trait ThriftStruct {
77
def write(oprot: TProtocol)
88
}
99

10+
trait ThriftResponse[Result] {
11+
def successField: Option[Result]
12+
def exceptionFields: Iterable[Option[ThriftException]]
13+
/**
14+
* Return the first nonempty exception field.
15+
*/
16+
def firstException(): Option[ThriftException] =
17+
exceptionFields.collectFirst(ThriftResponse.exceptionIsDefined)
18+
}
19+
20+
object ThriftResponse {
21+
private val exceptionIsDefined: PartialFunction[Option[ThriftException], ThriftException] = {
22+
case Some(exception) => exception
23+
}
24+
}
25+
1026
/**
1127
* Unions are tagged with this trait as well as with [[ThriftStruct]].
1228
*/
@@ -64,3 +80,27 @@ abstract class ThriftStructCodec3[T <: ThriftStruct] extends ThriftStructCodec[T
6480
}
6581

6682
}
83+
84+
/**
85+
* Metadata for a thrift method.
86+
*/
87+
trait ThriftMethod {
88+
/** A struct wrapping method arguments */
89+
type Args <: ThriftStruct
90+
/** The successful return type */
91+
type SuccessType
92+
/** Contains success or thrift application exceptions */
93+
type Result <: ThriftResponse[SuccessType] with ThriftStruct
94+
95+
/** Thrift method name */
96+
def name: String
97+
/** Thrift service name. A thrift service is a list of methods. */
98+
def serviceName: String
99+
/** Codec for the request args */
100+
def argsCodec: ThriftStructCodec3[Args]
101+
/** Codec for the response */
102+
def responseCodec: ThriftStructCodec3[Result]
103+
/** True for oneway thrift methods */
104+
def oneway: Boolean
105+
}
106+

‎scrooge-generator/src/main/resources/javagen/finagleClient.java‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ public __Stats(String name) {
120120

121121
{{/hasParent}}
122122
{{#functions}}
123-
{{>function}}
124-
{{/function}}
123+
{{#functionInfo}}
124+
{{>finagleClientFunction}}
125+
{{/functionInfo}}
126+
{{/functions}}
125127
}

‎scrooge-generator/src/main/resources/javagen/finagleClientFunction.java‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@
88
return _{{__stats_name}};
99
}
1010

11-
{{#headerInfo}}{{>header}}{{/headerInfo}} {
11+
{{#functionInfo}}{{>header}} {
1212
{{__stats_name}}().requestsCounter.incr();
1313

14-
Future<{{type}}> rv = this.service.apply(encodeRequest("{{clientFuncNameForWire}}", new {{ArgsStruct}}({{argNames}}))).flatMap(new Function<byte[], Future<{{type}}>>() {
14+
Future<{{type}}> rv = this.service.apply(encodeRequest("{{clientFuncNameForWire}}", new {{funcObjectName}}.Args({{argNames}}))).flatMap(new Function<byte[], Future<{{type}}>>() {
15+
1516
public Future<{{type}}> apply(byte[] in) {
1617
try {
17-
{{ResultStruct}} result = decodeResponse(in, {{ResultStruct}}.CODEC);
18+
{{funcObjectName}}.Result result = decodeResponse(in, {{funcObjectName}}.Result.CODEC);
19+
1820

1921
{{#hasThrows}}
2022
Exception exception = null;
@@ -60,3 +62,4 @@ public void onFailure(Throwable t) {
6062

6163
return rv;
6264
}
65+
{{/functionInfo}}

‎scrooge-generator/src/main/resources/javagen/finagleServiceFunction.java‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
addFunction("{{serviceFuncNameForWire}}", new Function2<TProtocol, Integer, Future<byte[]>>() {
22
public Future<byte[]> apply(TProtocol iprot, final Integer seqid) {
33
try {
4-
{{ArgsStruct}} args = {{ArgsStruct}}.decode(iprot);
4+
{{funcObjectName}}.Args args = {{funcObjectName}}.Args.decode(iprot);
55
iprot.readMessageEnd();
66
Future<{{typeName}}> result;
77
try {
@@ -11,13 +11,13 @@ public Future<byte[]> apply(TProtocol iprot, final Integer seqid) {
1111
}
1212
return result.flatMap(new Function<{{typeName}}, Future<byte[]>>() {
1313
public Future<byte[]> apply({{typeName}} value){
14-
return reply("{{serviceFuncNameForWire}}", seqid, new {{ResultStruct}}.Builder(){{^isVoid}}.success(value){{/isVoid}}.build());
14+
return reply("{{serviceFuncNameForWire}}", seqid, new {{funcObjectName}}.Result.Builder(){{^isVoid}}.success(value){{/isVoid}}.build());
1515
}
1616
}).rescue(new Function<Throwable, Future<byte[]>>() {
1717
public Future<byte[]> apply(Throwable t) {
1818
{{#exceptions}}
1919
if (t instanceof {{exceptionType}}) {
20-
return reply("{{ServiceName}}", seqid, new {{ResultStruct}}.Builder().{{fieldName}}(({{exceptionType}}) t).build());
20+
return reply("{{ServiceName}}", seqid, new {{funcObjectName}}.Result.Builder().{{fieldName}}(({{exceptionType}}) t).build());
2121
}
2222
{{/exceptions}}
2323
return Future.exception(t);
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
{{docstring}}
2-
public {{#generic}}{{generic}}<{{/generic}}{{typeName}}{{#generic}}>{{/generic}} {{funcName}}({{fieldParams}}){{#hasThrows}} throws {{#throws}}{{typeName}}{{/throws|, }}{{/hasThrows}}
2+
public {{#generic}}{{generic}}<{{/generic}}{{typeName}}{{#generic}}>{{/generic}} {{funcName}}({{fieldParams}}){{#hasThrows}} throws {{#throws}}{{throwType}}{{/throws|, }}{{/hasThrows}}

‎scrooge-generator/src/main/resources/javagen/service.java‎

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,19 @@ public FinagledService (
7171

7272
{{/withFinagle}}
7373

74-
{{#internalStructs}}
75-
{{#internalArgsStruct}}
74+
{{#thriftFunctions}}
75+
public static class {{funcObjectName}} {
76+
{{#functionArgsStruct}}
7677
{{>struct}}
77-
{{/internalArgsStruct}}
78+
{{/functionArgsStruct}}
7879
{{#internalResultStruct}}
7980
{{>struct}}
8081
{{/internalResultStruct}}
81-
{{/internalStructs}}
82+
{{#functionResultStruct}}
83+
{{>struct}}
84+
{{/functionResultStruct}}
85+
}
86+
{{/thriftFunctions}}
8287
{{#finagleClients}}
8388
{{>finagleClient}}
8489
{{/finagleClients}}

‎scrooge-generator/src/main/resources/scalagen/finagleClient.scala‎

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package {{package}}
22

3-
import com.twitter.finagle.{SourcedException, Service => FinagleService}
3+
import com.twitter.finagle.{SourcedException, Service}
44
import com.twitter.finagle.stats.{NullStatsReceiver, StatsReceiver}
55
import com.twitter.finagle.thrift.{Protocols, ThriftClientRequest}
66
import com.twitter.scrooge.{ThriftStruct, ThriftStructCodec}
@@ -17,10 +17,10 @@ import scala.language.higherKinds
1717
{{docstring}}
1818
@javax.annotation.Generated(value = Array("com.twitter.scrooge.Compiler"))
1919
class {{ServiceName}}$FinagleClient(
20-
{{#hasParent}}override {{/hasParent}}val service: FinagleService[ThriftClientRequest, Array[Byte]],
21-
{{#hasParent}}override {{/hasParent}}val protocolFactory: TProtocolFactory = Protocols.binaryFactory(),
22-
{{#hasParent}}override {{/hasParent}}val serviceName: String = "{{ServiceName}}",
23-
stats: StatsReceiver = NullStatsReceiver
20+
{{#hasParent}}override {{/hasParent}}val service: Service[ThriftClientRequest, Array[Byte]],
21+
{{#hasParent}}override {{/hasParent}}val protocolFactory: TProtocolFactory = Protocols.binaryFactory(),
22+
{{#hasParent}}override {{/hasParent}}val serviceName: String = "{{ServiceName}}",
23+
stats: StatsReceiver = NullStatsReceiver
2424
) extends {{#hasParent}}{{finagleClientParent}}(service, protocolFactory, serviceName, stats) with {{/hasParent}}{{ServiceName}}[Future] {
2525
import {{ServiceName}}._
2626
{{^hasParent}}
@@ -80,6 +80,7 @@ class {{ServiceName}}$FinagleClient(
8080
{{/hasParent}}
8181
private[this] val scopedStats = if (serviceName != "") stats.scope(serviceName) else stats
8282
{{#functions}}
83-
{{>function}}
83+
{{>finagleClientFunction}}
8484
{{/function}}
8585
}
86+

‎scrooge-generator/src/main/resources/scalagen/finagleClientFunction.scala‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ private[this] object {{__stats_name}} {
44
val FailuresCounter = scopedStats.scope("{{clientFuncNameForWire}}").counter("failures")
55
val FailuresScope = scopedStats.scope("{{clientFuncNameForWire}}").scope("failures")
66
}
7-
{{#headerInfo}}{{>header}}{{/headerInfo}} = {
7+
{{#functionInfo}}
8+
{{>header}} = {
89
{{__stats_name}}.RequestsCounter.incr()
9-
this.service(encodeRequest("{{clientFuncNameForWire}}", {{ArgsStruct}}({{argNames}}))) flatMap { response =>
10-
val result = decodeResponse(response, {{ResultStruct}})
10+
this.service(encodeRequest("{{clientFuncNameForWire}}", {{funcObjectName}}.Args({{argNames}}))) flatMap { response =>
11+
val result = decodeResponse(response, {{funcObjectName}}.Result)
1112
val exception: Future[Nothing] =
1213
{{#hasThrows}}
1314
if (false)
@@ -43,3 +44,4 @@ private[this] object {{__stats_name}} {
4344
{{__stats_name}}.FailuresScope.counter(Throwables.mkString(ex): _*).incr()
4445
}
4546
}
47+
{{/functionInfo}}

‎scrooge-generator/src/main/resources/scalagen/finagleService.scala‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package {{package}}
22

3-
import com.twitter.finagle.{Service => FinagleService, Thrift}
3+
import com.twitter.finagle.{Service, Thrift}
44
import com.twitter.finagle.stats.{NullStatsReceiver, StatsReceiver}
55
import com.twitter.scrooge.{ThriftStruct, TReusableMemoryTransport}
66
import com.twitter.util.Future

0 commit comments

Comments
 (0)