Skip to content

Fix exception on re-create server nodes #84

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 10 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
* fixed exception on re-create server nodes

## 1.7.0
* added environment credentials


## 1.6.0

* added retry function
Expand Down
50 changes: 44 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ or:
<?php

use YdbPlatform\Ydb\Ydb;
use YdbPlatform\Ydb\Auth\AccessTokenAuthentication;
use YdbPlatform\Ydb\Auth\Implement\AccessTokenAuthentication;

$config = [

Expand Down Expand Up @@ -134,7 +134,7 @@ or
<?php

use YdbPlatform\Ydb\Ydb;
use YdbPlatform\Ydb\Auth\OAuthTokenAuthentication;
use YdbPlatform\Ydb\Auth\Implement\OAuthTokenAuthentication;

$config = [

Expand Down Expand Up @@ -192,7 +192,7 @@ or
<?php

use YdbPlatform\Ydb\Ydb;
use YdbPlatform\Ydb\Auth\JwtWithPrivateKeyAuthentication;
use YdbPlatform\Ydb\Auth\Implement\JwtWithPrivateKeyAuthentication;

$config = [
'database' => '/ru-central1/b1glxxxxxxxxxxxxxxxx/etn0xxxxxxxxxxxxxxxx',
Expand Down Expand Up @@ -249,7 +249,7 @@ or:
<?php

use YdbPlatform\Ydb\Ydb;
use YdbPlatform\Ydb\Auth\JwtWithJsonAuthentication;
use YdbPlatform\Ydb\Auth\Implement\JwtWithJsonAuthentication;

$config = [
'database' => '/ru-central1/b1glxxxxxxxxxxxxxxxx/etn0xxxxxxxxxxxxxxxx',
Expand Down Expand Up @@ -299,7 +299,7 @@ or
<?php

use YdbPlatform\Ydb\Ydb;
use YdbPlatform\Ydb\Auth\MetadataAuthentication;
use YdbPlatform\Ydb\Auth\Implement\MetadataAuthentication;

$config = [

Expand Down Expand Up @@ -355,7 +355,7 @@ or:
<?php

use YdbPlatform\Ydb\Ydb;
use YdbPlatform\Ydb\Auth\AnonymousAuthentication;
use YdbPlatform\Ydb\Auth\Implement\AnonymousAuthentication;

$config = [

Expand All @@ -379,6 +379,44 @@ $config = [
$ydb = new Ydb($config);
```

## Determined by environment variables

```php
<?php

use YdbPlatform\Ydb\Ydb;
use YdbPlatform\Ydb\Auth\Implement\EnvironCredentials;

$config = [

// Database path
'database' => '/local',

// Database endpoint
'endpoint' => 'localhost:2136',

// Auto discovery (dedicated server only)
'discovery' => false,

// IAM config
'iam_config' => [
'insecure' => true,
],

'credentials' => new EnvironCredentials()
];

$ydb = new Ydb($config);
```

The following algorithm that is the same for YDB-PHP-SDK applies:

1. If the value of the `YDB_SERVICE_ACCOUNT_KEY_FILE_CREDENTIALS` environment variable is set, the **System Account Key** authentication mode is used and the key is taken from the file whose name is specified in this variable.
2. Otherwise, if the value of the `YDB_ANONYMOUS_CREDENTIALS` environment variable is set to 1, the anonymous authentication mode is used.
3. Otherwise, if the value of the `YDB_METADATA_CREDENTIALS` environment variable is set to 1, the **Metadata** authentication mode is used.
4. Otherwise, if the value of the `YDB_ACCESS_TOKEN_CREDENTIALS` environment variable is set, the **Access token** authentication mode is used, where the this variable value is passed.
5. Otherwise, the **Metadata** authentication mode is used.

# Usage

You should initialize a session from the Table service to start querying.
Expand Down
40 changes: 40 additions & 0 deletions src/Auth/EnvironCredentials.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

namespace YdbPlatform\Ydb\Auth;

use YdbPlatform\Ydb\Auth\Implement\AccessTokenAuthentication;
use YdbPlatform\Ydb\Auth\Implement\AnonymousAuthentication;
use YdbPlatform\Ydb\Auth\Implement\JwtWithJsonAuthentication;
use YdbPlatform\Ydb\Auth\Implement\MetadataAuthentication;

class EnvironCredentials extends \YdbPlatform\Ydb\Auth\Auth
{
/**
* @var Auth
*/
protected $auth;
public function __construct()
{
if ($jsonfile = getenv("YDB_SERVICE_ACCOUNT_KEY_FILE_CREDENTIALS")){
$this->auth = new JwtWithJsonAuthentication($jsonfile);
} elseif (getenv("YDB_ANONYMOUS_CREDENTIALS") == 1){
$this->auth = new AnonymousAuthentication();
} elseif (getenv("YDB_METADATA_CREDENTIALS") == 1){
$this->auth = new MetadataAuthentication();
} elseif ($token = getenv("YDB_ACCESS_TOKEN_CREDENTIALS")){
$this->auth = new AccessTokenAuthentication($token);
} else {
$this->auth = new MetadataAuthentication();
}
}

public function getTokenInfo(): TokenInfo
{
return $this->auth->getTokenInfo();
}

public function getName(): string
{
return $this->auth->getName();
}
}
2 changes: 2 additions & 0 deletions src/Discovery.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ class Discovery
*/
public function __construct(Ydb $ydb, LoggerInterface $logger = null)
{
$this->ydb = $ydb;

$this->client = new ServiceClient($ydb->endpoint(), [
'credentials' => $ydb->iam()->getCredentials(),
]);
Expand Down
2 changes: 2 additions & 0 deletions src/Operations.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ class Operations
*/
public function __construct(Ydb $ydb, LoggerInterface $logger = null)
{
$this->ydb = $ydb;

$this->client = new ServiceClient($ydb->endpoint(), [
'credentials' => $ydb->iam()->getCredentials(),
]);
Expand Down
13 changes: 11 additions & 2 deletions src/Retry/Retry.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace YdbPlatform\Ydb\Retry;

use Closure;
use Psr\Log\LoggerInterface;
use YdbPlatform\Ydb\Exception;
use YdbPlatform\Ydb\Exceptions\Grpc\DeadlineExceededException;
use YdbPlatform\Ydb\Exceptions\NonRetryableException;
Expand All @@ -22,9 +23,14 @@ class Retry

protected $fastBackOff;
protected $noBackOff;
/**
* @var LoggerInterface
*/
protected $logger;

public function __construct()
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
$this->timeoutMs = 2000;
$this->fastBackOff = new Backoff(6, 5);
$this->slowBackOff = new Backoff(6, 1000);
Expand Down Expand Up @@ -79,11 +85,14 @@ public function retry(Closure $closure, bool $idempotent)
$retryCount = 0;
$lastException = null;
while (microtime(true) < $startTime + $this->timeoutMs / 1000) {
$this->logger->debug("YDB: Run user function. Retry count: $retryCount. Ms: ".(microtime(true) - $startTime));
try {
return $closure();
} catch (Exception $e) {
$this->logger->warning("YDB: Received exception: ".$e->getMessage());
if (!$this->canRetry($e, $idempotent)){
throw $e;
$lastException = $e;
break;
}
$retryCount++;
$this->retryDelay($retryCount, $this->backoffType($e));
Expand Down
2 changes: 2 additions & 0 deletions src/Scheme.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ class Scheme
*/
public function __construct(Ydb $ydb, LoggerInterface $logger = null)
{
$this->ydb = $ydb;

$this->client = new ServiceClient($ydb->endpoint(), [
'credentials' => $ydb->iam()->getCredentials(),
]);
Expand Down
2 changes: 2 additions & 0 deletions src/Scripting.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ class Scripting
*/
public function __construct(Ydb $ydb, LoggerInterface $logger = null)
{
$this->ydb = $ydb;

$this->client = new ServiceClient($ydb->endpoint(), [
'credentials' => $ydb->iam()->getCredentials(),
]);
Expand Down
2 changes: 2 additions & 0 deletions src/Session.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ public function __construct(Table $table, $session_id)
{
$this->table = $table;

$this->ydb = $table->ydb();

$this->session_id = $session_id;

$this->client = $table->client();
Expand Down
13 changes: 13 additions & 0 deletions src/Table.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,20 @@ class Table
*/
private $retry;

/**
* @var Ydb
*/
protected $ydb;

/**
* @param Ydb $ydb
* @param LoggerInterface|null $logger
*/
public function __construct(Ydb $ydb, LoggerInterface $logger = null, Retry &$retry)
{

$this->ydb = $ydb;

$this->client = new ServiceClient($ydb->endpoint(), [
'credentials' => $ydb->iam()->getCredentials(),
]);
Expand Down Expand Up @@ -512,4 +520,9 @@ protected function deleteSession(string $exception): bool
\YdbPlatform\Ydb\Exceptions\Ydb\SessionBusyException::class
];

public function ydb()
{
return $this->ydb;
}

}
64 changes: 61 additions & 3 deletions src/Traits/RequestTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use YdbPlatform\Ydb\Issue;
use YdbPlatform\Ydb\Exception;
use YdbPlatform\Ydb\QueryResult;
use YdbPlatform\Ydb\Ydb;

trait RequestTrait
{
Expand All @@ -30,6 +31,13 @@ trait RequestTrait
*/
protected $last_request_try_count = 0;

/**
* @var Ydb
*/
protected $ydb;

protected $lastDiscovery = 0;

/**
* Make a request to the service with the given method.
*
Expand All @@ -41,6 +49,8 @@ trait RequestTrait
*/
protected function doRequest($service, $method, array $data = [])
{
$this->checkDiscovery();

$this->meta['x-ydb-auth-ticket'] = [$this->credentials->token()];

$this->saveLastRequest($service, $method, $data);
Expand Down Expand Up @@ -82,7 +92,7 @@ protected function doRequest($service, $method, array $data = [])
if (method_exists($call, 'wait')) {
list($response, $status) = $call->wait();

$this->checkGrpcStatus($service, $method, $status);
$this->handleGrpcStatus($service, $method, $status);

return $this->processResponse($service, $method, $response, $resultClass);
}
Expand All @@ -101,6 +111,11 @@ protected function doRequest($service, $method, array $data = [])
*/
protected function doStreamRequest($service, $method, $data = [])
{

$this->checkDiscovery();

$this->meta['x-ydb-auth-ticket'] = [$this->credentials->token()];

if (method_exists($this, 'take')) {
$this->take();
}
Expand Down Expand Up @@ -149,10 +164,23 @@ protected function doStreamRequest($service, $method, $data = [])
* @param object $status
* @throws Exception
*/
protected function checkGrpcStatus($service, $method, $status)
protected function handleGrpcStatus($service, $method, $status)
{
if (isset($status->code) && $status->code !== 0) {
$message = 'YDB ' . $service . ' ' . $method . ' (status code GRPC_' . $status->code . '): ' . ($status->details ?? 'no details');
try{
$this->ydb->discover();
}catch (\Exception $e){}
$message = 'YDB ' . $service . ' ' . $method . ' (status code GRPC_'.
(isset(self::$grpcExceptions[$status->code])?self::$grpcNames[$status->code]:$status->code)
.' ' . $status->code . '): ' . ($status->details ?? 'no details');
$endpoint = $this->ydb->endpoint();
$this->logger->error($message);
if ($this->ydb->needDiscovery()){
$endpoint = $this->ydb->cluster()->all()[array_rand($this->ydb->cluster()->all())]->endpoint();
}
$this->client = new $this->client($endpoint,[
'credentials' => $this->ydb->iam()->getCredentials()
]);
if (isset(self::$grpcExceptions[$status->code])) {
throw new self::$grpcExceptions[$status->code]($message);
} else {
Expand Down Expand Up @@ -272,6 +300,17 @@ protected function resetLastRequest()
$this->last_request_try_count = 0;
}

protected function checkDiscovery(){
if ($this->ydb->needDiscovery() && time()-$this->lastDiscovery>$this->ydb->discoveryInterval()){
try{
$this->lastDiscovery = time();
$this->ydb->discover();
} catch (\Exception $e){

}
}
}

private static $ydbExceptions = [
StatusCode::STATUS_CODE_UNSPECIFIED => \YdbPlatform\Ydb\Exceptions\Ydb\StatusCodeUnspecified::class,
StatusCode::BAD_REQUEST => \YdbPlatform\Ydb\Exceptions\Ydb\BadRequestException::class,
Expand Down Expand Up @@ -313,4 +352,23 @@ protected function resetLastRequest()
16 => \YdbPlatform\Ydb\Exceptions\Grpc\UnauthenticatedException::class
];

private static $grpcNames = [
1 => "CANCELLED",
2 => "UNKNOWN",
3 => "INVALID_ARGUMENT",
4 => "DEADLINE_EXCEEDED",
5 => "NOT_FOUND",
6 => "ALREADY_EXISTS",
7 => "PERMISSION_DENIED",
8 => "RESOURCE_EXHAUSTED",
9 => "FAILED_PRECONDITION",
10 => "ABORTED",
11 => "OUT_OF_RANGE",
12 => "UNIMPLEMENTED",
13 => "INTERNAL",
14 => "UNAVAILABLE",
15 => "DATA_LOSS",
16 => "UNAUTHENTICATED"
];

}
Loading