console: fix neon DB connection error due to env var propagation delay

PR-URL: https://github.com/hasura/graphql-engine-mono/pull/9430
Co-authored-by: Rikin Kachhia <54616969+rikinsk@users.noreply.github.com>
GitOrigin-RevId: ea407dae924ef2e88c4cb27b2207f52dc0fdf125
This commit is contained in:
Varun Dey 2023-06-12 23:29:01 +05:30 committed by hasura-bot
parent aeb8bc4c7a
commit d3fd27d9db
4 changed files with 92 additions and 36 deletions

View File

@ -59,7 +59,8 @@ const DBCreation: React.FC<Props> = ({
const dbName = allDataSources.length ? `herokuapp-${appName}` : 'default';
setIsSettingEnvVar(true);
setDBURLInEnvVars(dbURL)
.then(envVar => {
.then(data => {
const { envVar } = data;
setIsSettingEnvVar(false);
setCreatedEnvVar(envVar);
dispatch(

View File

@ -1,4 +1,4 @@
import { useState, useCallback } from 'react';
import { useCallback, useState } from 'react';
import { programmaticallyTraceError } from '../../../../../../features/Analytics';
import { Dispatch } from '../../../../../../types';
import {
@ -12,6 +12,11 @@ import {
connectionTypes,
getDefaultState,
} from '../../../DataSources/state';
import Globals from '../../../../../../Globals';
import {
controlPlaneClient,
FETCH_CONFIG_STATUS,
} from '../../../../../../features/ControlPlane';
type HasuraDBCreationPayload = {
envVar: string;
@ -105,7 +110,8 @@ export function useCreateHasuraCloudDatasource(
// This sets the database URL of the given Hasura project as an env var in Hasura Cloud project
setDBURLInEnvVars(dbUrl)
.then(envVar => {
.then(data => {
const { envVar, oldConfigHash } = data;
setState({
status: 'adding-data-source',
payload: {
@ -113,38 +119,19 @@ export function useCreateHasuraCloudDatasource(
dataSourceName,
},
});
/*
There's a downtime after env var updation.
So we verify the project health and attempt connecting datasource only after project is up
We start verifying the project health after a timeout of 5000 seconds,
because it could 2-3 seconds for the project to go down after the environment variable update
*/
setTimeout(() => {
verifyProjectHealthAndConnectDataSource(
const successCallback = () => {
executeConnect(
envVar,
// set success status when the data source gets added successfully
() => {
executeConnect(
envVar,
// set success status when the data source gets added successfully
() => {
setState({
status: 'success',
payload: {
envVar,
dataSourceName,
},
});
setState({
status: 'success',
payload: {
envVar,
dataSourceName,
},
// set error status when the data source gets added successfully
() => {
setState({
status: 'adding-data-source-failed',
payload: {
envVar,
dataSourceName,
},
});
}
);
});
},
// set error status if creating env var failed
() => {
@ -157,7 +144,61 @@ export function useCreateHasuraCloudDatasource(
});
}
);
}, 5000);
};
const errorCallback = () => {
setState({
status: 'adding-data-source-failed',
payload: {
envVar,
dataSourceName,
},
});
};
/**
* Getting a success response on adding an env var for a tenant on lux does not
* mean that the change has propagated to all workers of that tenant.
*
* If the change has not propagated to a worker to which the `pg_add_source` request is routed to,
* the server would throw an `inconsistent_object` error as the new env var will not be found.
*
* To handle this, we wait for the changes to be propagated to all
* workers of a tenant before attempting to connect the DB.
*
* We do that by verifying that the new config hash has been set
* for all workers of the tenant using the `config_status` table.
*
* Additionally add a timeout interval with retries as an additional
* redundancy since it throws CORS error locally
*/
const { unsubscribe } = controlPlaneClient.subscribe(
FETCH_CONFIG_STATUS,
{
tenantId: Globals.hasuraCloudTenantId,
},
data => {
if (
// check if all workers are successfully configured with the new hash
data.config_status.every(
(config: { hash: string; message: string }) =>
config.message === 'Service configured successfully' &&
config.hash !== oldConfigHash
)
) {
setTimeout(() => {
verifyProjectHealthAndConnectDataSource(
successCallback,
errorCallback
);
}, 1000);
unsubscribe();
}
},
error => {
errorCallback();
unsubscribe();
}
);
})
.catch(error => {
// if adding env var fails unexpectedly, set the error state
@ -189,7 +230,7 @@ export function useCreateHasuraCloudDatasource(
});
});
}
}, [dbUrl, dataSourceName, state]);
}, [dbUrl, dataSourceName, executeConnect]);
return {
state,

View File

@ -129,7 +129,7 @@ export const setDBURLInEnvVars = (dbURL: string) => {
value: dbURL,
},
]).then(() => {
return emptyEnvVar;
return { envVar: emptyEnvVar, oldConfigHash: hash };
});
})
.catch(e => {

View File

@ -263,3 +263,17 @@ export const ADD_SCHEMA_REGISTRY_FEATURE_REQUEST = gql(`
}
}
`);
export const FETCH_CONFIG_STATUS = gql(`
subscription FetchConfigStatus($tenantId: uuid!) {
config_status(
where: {
tenant_id: { _eq: $tenantId }
is_active: { _eq: true }
}
) {
hash
message
}
}
`);