2017-09-24 15 views
0

私はノードjsサーバを実行しており、自動スケールするように設定しています。このサーバは、私がバージョンアップしたいAWSのpostgresqlデータベースにアクセスしています。ここでの目標は、必要に応じてテーブルを変更するコードでサーバーの更新をプッシュできるようにすることです。私がこれまで行ってきたことは、サーバーが始動するときにデータベースに接続するBaseDatabaseクラスが作成されています(私はexpress jsアプリケーションを開始する前にネットワークトラフィックがまだありません)。これは、私が別のポートで私のサーバーの複数のインスタンスを実行することができますし、私は働くすべての私のテストのためにノードjsサーバでのpostgresqlデータベースアクセスの同期

let transactionComplete = false; 
try { 
    await client.query("BEGIN"); 
    let currentVersion = await client.query("SELECT current_setting('info.version')::int"); 
    if (currentVersion < version) { 
    try { 
     await upgradeDatabase(client, currentVersion, version); 
    } catch (e) { 
     // Handle error 
    } 
    } 
    await client.query(`SELECT set_config('info.version', ${version}, false)`); 
    transactionComplete = true; 
} catch (e) { 
    try { 
    await createDatabase(client); 
    transactionComplete = true; 
    } catch (e) { 
    // Handle error 
    } 
} finally { 
    if (transactionComplete) { 
    await client.query('COMMIT'); 
    } else { 
    await client.query('ROLLBACK'); 
    } 
    client.release(); 
} 

:データベースへの接続時に

は、私が(typescriptです中)を使用して現在のバージョンを確認します私のデータベースを一度しか作成/更新することはできません。私はちょうど幸運だと思う。私はこれが単一の取引であっても、最後の COMMITの前に解決する最初の SELECTを条件としていると思います。これを行う正しい方法は、私のクエリ内の条件付き条件付きですべてを一緒に実行することだと思われます。

DO $$ 
BEGIN 
IF (SELECT current_setting('info.version')::int) < ${version} THEN 
    RAISE NOTICE 'database requires update'; 
END IF; 
END; 
$$; 

上記の作品と私は私があれば内部の私のアップグレード文を取得することができれば、完全にアトミックだろうと信じて:私のようなものを作成することができました。問題は私がinfo.versionを照会するまで必要なステートメントがわからないことです。これらのクエリを実行している間にデータベース全体をロックする方法はありますか?または、私のすべてのノードjsサーバーインスタンスを同期することができますか?それとも私が考えていない何か?

ここでの最終目標は、コードにデータベースの変更を加えることができ、新しいサーバーバージョンをプッシュするときに一度実行されるということです。データベースを変更する前に私のチームとコードレビューなどをしたり、私のプロダクト環境をローカルに複製する再現可能な方法を持っています。

+0

を事実対容疑で質問を投稿が空に穴を突っついています。最初に問題を特定し、解決策を探します。 –

+0

私は私が従うか分からない。問題は、データベースをバージョンアップしてJavaScriptを使用して変更できるようにすることです。私の懸念は、私が持っているものは同期化に耐えられないということです。私の質問は、私が安全なやり方でやろうとして同じ操作をどうやって行うことができるかということです。 – TheHebrewHammer

答えて

0

私が働いているように見えるソリューション見つけた:

// This is actually a bit more complex to allow for the first instance when 
// info.version is not yet defined. 
let currentVersion: number = await client.query(
    "SELECT current_setting('info.version')"); 
if (this.version === currentVersion) { 
    return; 
} 
let query: string = currentVersion === null 
    ? await this.onCreate(client) 
    : await this.onUpgrade(client currentVersion, this.version); 
query = this.getSqlStatment(currentVersion, this.version, query); 
try { 
    await client.query(query); 
} catch (e) { 
} finally { 
    client.release(); 
} 

private getSqlStatement(fromVersion: number, toVersion: number, query: string): string { 
    return `DO \$\$ 
DECLARE version integer; 
BEGIN 
version := current_setting('info.version')::integer; 
EXCEPTION 
    WHEN SQLSTATE '42704' THEN version := NULL; 
IF version ${fromVersion ? `= ${fromVersion} : "IS NULL"} THEN 
    ${query} 
    PERFORM set_config('info.version', '${toVersion}', false); 
END IF; 
END; 
\$\$`; 
} 
関連する問題