RetryParamsTest.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. <?php
  2. namespace YdbPlatform\Ydb\Test;
  3. use YdbPlatform\Ydb\Auth\Implement\AnonymousAuthentication;
  4. use YdbPlatform\Ydb\Exception;
  5. use YdbPlatform\Ydb\Exceptions\Grpc\AbortedException;
  6. use YdbPlatform\Ydb\Exceptions\Grpc\AlreadyExistsException;
  7. use YdbPlatform\Ydb\Exceptions\Grpc\CanceledException;
  8. use YdbPlatform\Ydb\Exceptions\Grpc\DataLossException;
  9. use YdbPlatform\Ydb\Exceptions\Grpc\DeadlineExceededException;
  10. use YdbPlatform\Ydb\Exceptions\Grpc\FailedPreconditionException;
  11. use YdbPlatform\Ydb\Exceptions\Grpc\InternalException;
  12. use YdbPlatform\Ydb\Exceptions\Grpc\InvalidArgumentException;
  13. use YdbPlatform\Ydb\Exceptions\Grpc\NotFoundException;
  14. use YdbPlatform\Ydb\Exceptions\Grpc\OutOfRangeException;
  15. use YdbPlatform\Ydb\Exceptions\Grpc\ResourceExhaustedException;
  16. use YdbPlatform\Ydb\Exceptions\Grpc\UnavailableException;
  17. use YdbPlatform\Ydb\Exceptions\Grpc\UnimplementedException;
  18. use YdbPlatform\Ydb\Exceptions\Grpc\UnknownException;
  19. use YdbPlatform\Ydb\Exceptions\Ydb\BadRequestException;
  20. use YdbPlatform\Ydb\Exceptions\Ydb\InternalErrorException;
  21. use YdbPlatform\Ydb\Exceptions\Ydb\StatusCodeUnspecified;
  22. use YdbPlatform\Ydb\Exceptions\Ydb\UnauthorizedException;
  23. use YdbPlatform\Ydb\Logger\SimpleStdLogger;
  24. use YdbPlatform\Ydb\Retry\Backoff;
  25. use YdbPlatform\Ydb\Retry\RetryParams;
  26. use YdbPlatform\Ydb\Table;
  27. use YdbPlatform\Ydb\Ydb;
  28. use YdbPlatform\Ydb\Retry\Retry;
  29. class RetrySubclass extends Retry{
  30. public function canRetry(\Exception $e, bool $idempotent)
  31. {
  32. return parent::canRetry($e, $idempotent);
  33. }
  34. public function backoffType(string $e): Backoff
  35. {
  36. return parent::backoffType($e);
  37. }
  38. }
  39. class TableSubclass extends Table{
  40. public function deleteSession(string $exception): bool
  41. {
  42. return parent::deleteSession($exception);
  43. }
  44. }
  45. class RetryParamsTest extends \PHPUnit\Framework\TestCase
  46. {
  47. protected const FAST = 5;
  48. protected const SLOW = 20;
  49. protected const BACKOFF_TYPE = [
  50. 0 => "noBackoff",
  51. self::FAST => "fastBackoff",
  52. self::SLOW => "slowBackoff"
  53. ];
  54. protected $errsToCheck = [
  55. [
  56. "class" => DeadlineExceededException::class,
  57. "deleteSession" => true,
  58. "backoffTime" => self::FAST,
  59. "retry" => [
  60. "idempotent" => true,
  61. "nonIdempotent" => false
  62. ]
  63. ],
  64. [
  65. "class" => CanceledException::class,
  66. "deleteSession" => true,
  67. "backoffTime" => self::FAST,
  68. "retry" => [
  69. "idempotent" => true,
  70. "nonIdempotent" => false
  71. ]
  72. ],
  73. [
  74. "class" => UnknownException::class,
  75. "deleteSession" => true,
  76. "backoffTime" => 0,
  77. "retry" => [
  78. "idempotent" => false,
  79. "nonIdempotent" => false
  80. ]
  81. ],
  82. [
  83. "class" => InvalidArgumentException::class,
  84. "deleteSession" => true,
  85. "backoffTime" => 0,
  86. "retry" => [
  87. "idempotent" => false,
  88. "nonIdempotent" => false
  89. ]
  90. ],
  91. [
  92. "class" => NotFoundException::class,
  93. "deleteSession" => true,
  94. "backoffTime" => 0,
  95. "retry" => [
  96. "idempotent" => false,
  97. "nonIdempotent" => false
  98. ]
  99. ],
  100. [
  101. "class" => AlreadyExistsException::class,
  102. "deleteSession" => true,
  103. "backoffTime" => 0,
  104. "retry" => [
  105. "idempotent" => false,
  106. "nonIdempotent" => false
  107. ]
  108. ],
  109. [
  110. "class" => ResourceExhaustedException::class,
  111. "deleteSession" => false,
  112. "backoffTime" => self::SLOW,
  113. "retry" => [
  114. "idempotent" => true,
  115. "nonIdempotent" => true
  116. ]
  117. ],
  118. [
  119. "class" => FailedPreconditionException::class,
  120. "deleteSession" => true,
  121. "backoffTime" => 0,
  122. "retry" => [
  123. "idempotent" => false,
  124. "nonIdempotent" => false
  125. ]
  126. ],
  127. [
  128. "class" => AbortedException::class,
  129. "deleteSession" => true,
  130. "backoffTime" => 0,
  131. "retry" => [
  132. "idempotent" => true,
  133. "nonIdempotent" => true
  134. ]
  135. ],
  136. [
  137. "class" => OutOfRangeException::class,
  138. "deleteSession" => false,
  139. "backoffTime" => 0,
  140. "retry" => [
  141. "idempotent" => false,
  142. "nonIdempotent" => false
  143. ]
  144. ],
  145. [
  146. "class" => UnimplementedException::class,
  147. "deleteSession" => true,
  148. "backoffTime" => 0,
  149. "retry" => [
  150. "idempotent" => false,
  151. "nonIdempotent" => false
  152. ]
  153. ],
  154. [
  155. "class" => InternalException::class,
  156. "deleteSession" => true,
  157. "backoffTime" => self::FAST,
  158. "retry" => [
  159. "idempotent" => true,
  160. "nonIdempotent" => false
  161. ]
  162. ],
  163. [
  164. "class" => UnavailableException::class,
  165. "deleteSession" => true,
  166. "backoffTime" => self::FAST,
  167. "retry" => [
  168. "idempotent" => true,
  169. "nonIdempotent" => false
  170. ]
  171. ],
  172. [
  173. "class" => DataLossException::class,
  174. "deleteSession" => true,
  175. "backoffTime" => 0,
  176. "retry" => [
  177. "idempotent" => false,
  178. "nonIdempotent" => false
  179. ]
  180. ],
  181. [
  182. "class" => DataLossException::class,
  183. "deleteSession" => true,
  184. "backoffTime" => 0,
  185. "retry" => [
  186. "idempotent" => false,
  187. "nonIdempotent" => false
  188. ]
  189. ],
  190. [
  191. "class" => StatusCodeUnspecified::class,
  192. "deleteSession" => true,
  193. "backoffTime" => 0,
  194. "retry" => [
  195. "idempotent" => false,
  196. "nonIdempotent" => false
  197. ]
  198. ],
  199. [
  200. "class" => BadRequestException::class,
  201. "deleteSession" => false,
  202. "backoffTime" => 0,
  203. "retry" => [
  204. "idempotent" => false,
  205. "nonIdempotent" => false
  206. ]
  207. ],
  208. [
  209. "class" => UnauthorizedException::class,
  210. "deleteSession" => false,
  211. "backoffTime" => 0,
  212. "retry" => [
  213. "idempotent" => false,
  214. "nonIdempotent" => false
  215. ]
  216. ],
  217. [
  218. "class" => InternalErrorException::class,
  219. "deleteSession" => false,
  220. "backoffTime" => 0,
  221. "retry" => [
  222. "idempotent" => false,
  223. "nonIdempotent" => false
  224. ]
  225. ],
  226. [
  227. "class" => \YdbPlatform\Ydb\Exceptions\Ydb\AbortedException::class,
  228. "deleteSession" => false,
  229. "backoffTime" => self::FAST,
  230. "retry" => [
  231. "idempotent" => true,
  232. "nonIdempotent" => true
  233. ]
  234. ],
  235. [
  236. "class" => \YdbPlatform\Ydb\Exceptions\Ydb\UnavailableException::class,
  237. "deleteSession" => false,
  238. "backoffTime" => self::FAST,
  239. "retry" => [
  240. "idempotent" => true,
  241. "nonIdempotent" => true
  242. ]
  243. ],
  244. [
  245. "class" => \YdbPlatform\Ydb\Exceptions\Ydb\OverloadedException::class,
  246. "deleteSession" => false,
  247. "backoffTime" => self::SLOW,
  248. "retry" => [
  249. "idempotent" => true,
  250. "nonIdempotent" => true
  251. ]
  252. ],
  253. [
  254. "class" => \YdbPlatform\Ydb\Exceptions\Ydb\SchemeErrorException::class,
  255. "deleteSession" => false,
  256. "backoffTime" => 0,
  257. "retry" => [
  258. "idempotent" => false,
  259. "nonIdempotent" => false
  260. ]
  261. ],
  262. [
  263. "class" => \YdbPlatform\Ydb\Exceptions\Ydb\GenericErrorException::class,
  264. "deleteSession" => false,
  265. "backoffTime" => 0,
  266. "retry" => [
  267. "idempotent" => false,
  268. "nonIdempotent" => false
  269. ]
  270. ],
  271. [
  272. "class" => \YdbPlatform\Ydb\Exceptions\Ydb\TimeoutException::class,
  273. "deleteSession" => false,
  274. "backoffTime" => 0,
  275. "retry" => [
  276. "idempotent" => false,
  277. "nonIdempotent" => false
  278. ]
  279. ],
  280. [
  281. "class" => \YdbPlatform\Ydb\Exceptions\Ydb\BadSessionException::class,
  282. "deleteSession" => true,
  283. "backoffTime" => 0,
  284. "retry" => [
  285. "idempotent" => true,
  286. "nonIdempotent" => true
  287. ]
  288. ],
  289. [
  290. "class" => \YdbPlatform\Ydb\Exceptions\Ydb\PreconditionFailedException::class,
  291. "deleteSession" => false,
  292. "backoffTime" => 0,
  293. "retry" => [
  294. "idempotent" => false,
  295. "nonIdempotent" => false
  296. ]
  297. ],
  298. [
  299. "class" => \YdbPlatform\Ydb\Exceptions\Ydb\AlreadyExistsException::class,
  300. "deleteSession" => false,
  301. "backoffTime" => 0,
  302. "retry" => [
  303. "idempotent" => false,
  304. "nonIdempotent" => false
  305. ]
  306. ],
  307. [
  308. "class" => \YdbPlatform\Ydb\Exceptions\Ydb\NotFoundException::class,
  309. "deleteSession" => false,
  310. "backoffTime" => 0,
  311. "retry" => [
  312. "idempotent" => false,
  313. "nonIdempotent" => false
  314. ]
  315. ],
  316. [
  317. "class" => \YdbPlatform\Ydb\Exceptions\Ydb\SessionExpiredException::class,
  318. "deleteSession" => true,
  319. "backoffTime" => 0,
  320. "retry" => [
  321. "idempotent" => false,
  322. "nonIdempotent" => false
  323. ]
  324. ],
  325. [
  326. "class" => \YdbPlatform\Ydb\Exceptions\Ydb\CancelledException::class,
  327. "deleteSession" => false,
  328. "backoffTime" => self::FAST,
  329. "retry" => [
  330. "idempotent" => false,
  331. "nonIdempotent" => false
  332. ]
  333. ],
  334. [
  335. "class" => \YdbPlatform\Ydb\Exceptions\Ydb\UndeterminedException::class,
  336. "deleteSession" => false,
  337. "backoffTime" => self::FAST,
  338. "retry" => [
  339. "idempotent" => true,
  340. "nonIdempotent" => false
  341. ]
  342. ],
  343. [
  344. "class" => \YdbPlatform\Ydb\Exceptions\Ydb\UnsupportedException::class,
  345. "deleteSession" => false,
  346. "backoffTime" => 0,
  347. "retry" => [
  348. "idempotent" => false,
  349. "nonIdempotent" => false
  350. ]
  351. ],
  352. [
  353. "class" => \YdbPlatform\Ydb\Exceptions\Ydb\SessionBusyException::class,
  354. "deleteSession" => true,
  355. "backoffTime" => self::FAST,
  356. "retry" => [
  357. "idempotent" => true,
  358. "nonIdempotent" => true
  359. ]
  360. ],
  361. ];
  362. public function testBackoffTypesAndDeleteSessionOnException(){
  363. $retryParams = new RetryParams(1000, new Backoff(6,self::FAST),
  364. new Backoff(6,self::SLOW));
  365. $logger = new SimpleStdLogger(7);
  366. $retry = (new RetrySubclass($logger))->withParams($retryParams);
  367. $table = new TableSubclass(new Ydb(["credentials"=>new AnonymousAuthentication()]), $logger, $retry);
  368. foreach ($this->errsToCheck as $error) {
  369. $exception = new $error["class"]();
  370. $resultDeleteSession = $table->deleteSession($error["class"]) ? "true" : "false";
  371. $wantDeleteSession = $error["deleteSession"] ? "true" : "false";
  372. self::assertEquals($wantDeleteSession, $resultDeleteSession,
  373. "{$error["class"]}: unexpected delete session status: $resultDeleteSession, want: $wantDeleteSession");
  374. $resultRetryIdempotent = $retry->canRetry($exception, true) ? "true" : "false";
  375. $wantRetryIdempotent = $error["retry"]["idempotent"] ? "true" : "false";
  376. self::assertEquals($wantRetryIdempotent, $resultRetryIdempotent,
  377. "{$error["class"]}: unexpected must retry idempotent operation status: $resultRetryIdempotent, want: $wantRetryIdempotent");
  378. $resultRetryNonIdempotent = $retry->canRetry($exception, false) ? "true" : "false";
  379. $wantRetryNonIdempotent = $error["retry"]["nonIdempotent"] ? "true" : "false";
  380. self::assertEquals($wantRetryNonIdempotent, $resultRetryNonIdempotent,
  381. "{$error["class"]}: unexpected must retry non-idempotent operation status: $resultDeleteSession, want: $wantDeleteSession");
  382. if($error["retry"]["idempotent"]){
  383. $resultBackoff = $retry->backoffType($error["class"])->getBackoffSlotMillis();
  384. $wantBackoff = $error["backoffTime"];
  385. self::assertEquals($wantBackoff, $resultBackoff,
  386. "{$error["class"]}: unexpected backoff type: ".
  387. self::BACKOFF_TYPE[$resultBackoff].", want: ".
  388. self::BACKOFF_TYPE[$wantBackoff]);
  389. }
  390. }
  391. }
  392. }