Skip to content

Commit b5a480e

Browse files
committed
Merge pull request #4 from codacy/improve-exception-handling
catch exceptions and smaller thread pool
2 parents dcc542c + 062bd58 commit b5a480e

File tree

1 file changed

+50
-14
lines changed

1 file changed

+50
-14
lines changed

src/main/scala/com/codacy/client/bitbucket/client/BitbucketClient.scala

Lines changed: 50 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
package com.codacy.client.bitbucket.client
22

3+
import java.util.concurrent.{SynchronousQueue, ThreadPoolExecutor, TimeUnit}
4+
35
import com.codacy.client.bitbucket.util.HTTPStatusCodes
4-
import com.ning.http.client.AsyncHttpClient
6+
import com.ning.http.client.AsyncHttpClientConfig
57
import play.api.libs.json.{JsValue, Json, Reads}
68
import play.api.libs.oauth._
7-
import play.api.libs.ws.ning.NingWSClient
9+
import play.api.libs.ws.DefaultWSClientConfig
10+
import play.api.libs.ws.ning.{NingAsyncHttpClientConfigBuilder, NingWSClient}
811

912
import scala.concurrent.Await
1013
import scala.concurrent.duration.{Duration, SECONDS}
14+
import scala.util.{Failure, Properties, Success, Try}
1115

1216
class BitbucketClient(key: String, secretKey: String, token: String, secretToken: String) {
1317

@@ -50,9 +54,7 @@ class BitbucketClient(key: String, secretKey: String, token: String, secretToken
5054
/*
5155
* Does an API post
5256
*/
53-
def post[T](request: Request[T], values: JsValue)(implicit reader: Reads[T]): RequestResponse[T] = {
54-
val client = new NingWSClient(new AsyncHttpClient().getConfig)
55-
57+
def post[T](request: Request[T], values: JsValue)(implicit reader: Reads[T]): RequestResponse[T] = withClientRequest { client =>
5658
val jpromise = client.url(request.url)
5759
.sign(requestSigner)
5860
.withFollowRedirects(follow = true)
@@ -73,14 +75,11 @@ class BitbucketClient(key: String, secretKey: String, token: String, secretToken
7375
RequestResponse[T](None, result.statusText, hasError = true)
7476
}
7577

76-
client.close()
7778
value
7879
}
7980

8081
/* copy paste from post ... */
81-
def delete[T](url: String): RequestResponse[Boolean] = {
82-
val client = new NingWSClient(new AsyncHttpClient().getConfig)
83-
82+
def delete[T](url: String): RequestResponse[Boolean] = withClientRequest { client =>
8483
val jpromise = client.url(url)
8584
.sign(requestSigner)
8685
.withFollowRedirects(follow = true)
@@ -93,13 +92,10 @@ class BitbucketClient(key: String, secretKey: String, token: String, secretToken
9392
RequestResponse[Boolean](None, result.statusText, hasError = true)
9493
}
9594

96-
client.close()
9795
value
9896
}
9997

100-
private def get(url: String): Either[ResponseError, JsValue] = {
101-
val client = new NingWSClient(new AsyncHttpClient().getConfig)
102-
98+
private def get(url: String): Either[ResponseError, JsValue] = withClientEither { client =>
10399
val jpromise = client.url(url)
104100
.sign(requestSigner)
105101
.withFollowRedirects(follow = true)
@@ -113,7 +109,6 @@ class BitbucketClient(key: String, secretKey: String, token: String, secretToken
113109
Left(ResponseError(java.util.UUID.randomUUID().toString, result.statusText, result.statusText))
114110
}
115111

116-
client.close()
117112
value
118113
}
119114

@@ -127,4 +122,45 @@ class BitbucketClient(key: String, secretKey: String, token: String, secretToken
127122
Left(error)
128123
}.getOrElse(Right(json))
129124
}
125+
126+
private def withClientEither[T](block: NingWSClient => Either[ResponseError, T]): Either[ResponseError, T] = {
127+
withClient(block) match {
128+
case Success(res) => res
129+
case Failure(error) =>
130+
Left(ResponseError("Request failed", getFullStackTrace(error), error.getMessage))
131+
}
132+
}
133+
134+
private def withClientRequest[T](block: NingWSClient => RequestResponse[T]): RequestResponse[T] = {
135+
withClient(block) match {
136+
case Success(res) => res
137+
case Failure(error) =>
138+
val statusMessage =
139+
s"""
140+
|Failed request:
141+
|
142+
|${getFullStackTrace(error)}
143+
""".stripMargin
144+
RequestResponse[T](None, statusMessage, hasError = true)
145+
}
146+
}
147+
148+
private def withClient[T](block: NingWSClient => T): Try[T] = {
149+
val config = new NingAsyncHttpClientConfigBuilder(DefaultWSClientConfig()).build()
150+
val clientConfig = new AsyncHttpClientConfig.Builder(config)
151+
.setExecutorService(new ThreadPoolExecutor(0, 2, 30L, TimeUnit.SECONDS, new SynchronousQueue[Runnable]))
152+
.build()
153+
val client = new NingWSClient(clientConfig)
154+
val result = Try(block(client))
155+
client.close()
156+
result
157+
}
158+
159+
private def getFullStackTrace(throwableOpt: Throwable, accumulator: String = ""): String = {
160+
Option(throwableOpt).map { throwable =>
161+
val newAccumulator = s"$accumulator${Properties.lineSeparator}${throwable.getStackTraceString}"
162+
getFullStackTrace(throwable.getCause, newAccumulator)
163+
}.getOrElse(accumulator)
164+
}
165+
130166
}

0 commit comments

Comments
 (0)