Skip to content

Commit 2b38bf4

Browse files
authored
Merge pull request elizaOS#3913 from 0xbbjoker/0xbbjoker/migrations-race-condition
fix: migration race condition
2 parents 132479c + 61d18d3 commit 2b38bf4

File tree

5 files changed

+33
-63
lines changed

5 files changed

+33
-63
lines changed

bun.lock

+2-2
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@
7474
"name": "@elizaos/cli",
7575
"version": "1.0.0-alpha.35",
7676
"bin": {
77-
"elizaos": "./dist/index.js",
77+
"elizaos": "./dist/index.js"
7878
},
7979
"dependencies": {
8080
"@electric-sql/pglite": "^0.2.17",
@@ -216,7 +216,7 @@
216216
"name": "create-eliza",
217217
"version": "1.0.0-alpha.35",
218218
"bin": {
219-
"create-eliza": "index.mjs",
219+
"create-eliza": "index.mjs"
220220
},
221221
},
222222
"packages/docs": {

packages/cli/src/server/index.ts

+23-12
Original file line numberDiff line numberDiff line change
@@ -94,23 +94,34 @@ export class AgentServer {
9494
"00000000-0000-0000-0000-000000000002",
9595
);
9696

97-
// Initialize the database
98-
this.database
99-
.init()
100-
.then(() => {
101-
logger.success("Database initialized successfully");
102-
this.initializeServer(options);
103-
})
104-
.catch((error) => {
105-
logger.error("Failed to initialize database:", error);
106-
throw error;
107-
});
97+
// Database initialization moved to initialize() method
10898
} catch (error) {
10999
logger.error("Failed to initialize AgentServer:", error);
110100
throw error;
111101
}
102+
}
112103

113-
logger.info(`Server started at ${AGENT_RUNTIME_URL}`);
104+
/**
105+
* Initializes the database and server.
106+
*
107+
* @param {ServerOptions} [options] - Optional server options.
108+
* @returns {Promise<void>} A promise that resolves when initialization is complete.
109+
*/
110+
public async initialize(options?: ServerOptions): Promise<void> {
111+
try {
112+
// Initialize the database with await
113+
await this.database.init();
114+
logger.success("Database initialized successfully");
115+
116+
// Only continue with server initialization after database is ready
117+
await this.initializeServer(options);
118+
119+
// Move this message here to be more accurate
120+
logger.info(`Server started at ${AGENT_RUNTIME_URL}`);
121+
} catch (error) {
122+
logger.error("Failed to initialize:", error);
123+
throw error;
124+
}
114125
}
115126

116127
/**

packages/plugin-sql/drizzle.config.ts

-5
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,6 @@ export default defineConfig({
77
dialect: "postgresql",
88
schema: "./src/schema/index.ts",
99
out: "./drizzle/migrations",
10-
migrations: {
11-
table: "__drizzle_migrations",
12-
schema: "public",
13-
prefix: "timestamp",
14-
},
1510
dbCredentials: {
1611
url: process.env.POSTGRES_URL || "file://../../pglite",
1712
},

packages/plugin-sql/src/pg-lite/manager.ts

+4-22
Original file line numberDiff line numberDiff line change
@@ -103,23 +103,6 @@ export class PGliteClientManager implements IDatabaseClientManager<PGlite> {
103103
});
104104
}
105105

106-
/**
107-
* Asynchronously checks if migrations exist in the database.
108-
* @returns {Promise<boolean>} A Promise that resolves to true if migrations exist, otherwise false.
109-
*/
110-
private async hasMigrations(): Promise<boolean> {
111-
try {
112-
const result = await this.client.query(
113-
"SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = '__drizzle_migrations')"
114-
);
115-
return (result.rows[0] as any).exists;
116-
} catch (error) {
117-
logger.error("Failed to check migrations:", error);
118-
return false;
119-
}
120-
}
121-
122-
123106
/**
124107
* Initializes the client for PGlite.
125108
*
@@ -158,20 +141,19 @@ export class PGliteClientManager implements IDatabaseClientManager<PGlite> {
158141

159142
/**
160143
* Asynchronously runs database migrations using Drizzle.
144+
*
145+
* Drizzle will first check if the migrations are already applied.
146+
* If there is a diff between database schema and migrations, it will apply the migrations.
147+
* If they are already applied, it will skip them.
161148
*
162149
* @returns {Promise<void>} A Promise that resolves once the migrations are completed successfully.
163150
*/
164151
async runMigrations(): Promise<void> {
165152
try {
166153
const db = drizzle(this.client);
167-
if (await this.hasMigrations()) {
168-
logger.info("Migrations already exist, skipping...");
169-
return;
170-
}
171154
await migrate(db, {
172155
migrationsFolder: path.resolve(__dirname, "../drizzle/migrations"),
173156
});
174-
logger.info("Migrations completed successfully!");
175157
} catch (error) {
176158
logger.error("Failed to run database migrations (pglite):", error);
177159
// throw error;

packages/plugin-sql/src/pg/manager.ts

+4-22
Original file line numberDiff line numberDiff line change
@@ -178,22 +178,6 @@ export class PostgresConnectionManager
178178
await this.cleanup();
179179
}
180180

181-
/**
182-
* Asynchronously checks if migrations exist in the database.
183-
* @returns {Promise<boolean>} A Promise that resolves to true if migrations exist, otherwise false.
184-
*/
185-
private async hasMigrations(): Promise<boolean> {
186-
try {
187-
const result = await this.pool.query(
188-
"SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = '__drizzle_migrations')"
189-
);
190-
return result.rows[0].exists;
191-
} catch (error) {
192-
logger.error("Failed to check migrations:", error);
193-
return false;
194-
}
195-
}
196-
197181
/**
198182
* Cleans up and closes the database pool.
199183
* @returns {Promise<void>} A Promise that resolves when the database pool is closed.
@@ -210,22 +194,20 @@ export class PostgresConnectionManager
210194
/**
211195
* Asynchronously runs database migrations using the Drizzle library.
212196
*
197+
* Drizzle will first check if the migrations are already applied.
198+
* If there is a diff between database schema and migrations, it will apply the migrations.
199+
* If they are already applied, it will skip them.
200+
*
213201
* @returns {Promise<void>} A Promise that resolves once the migrations are completed successfully.
214202
*/
215203
async runMigrations(): Promise<void> {
216204
try {
217205
const db = drizzle(this.pool);
218-
if (await this.hasMigrations()) {
219-
logger.info("Migrations already exist, skipping...");
220-
return;
221-
}
222206
await migrate(db, {
223207
migrationsFolder: path.resolve(__dirname, "../drizzle/migrations"),
224208
});
225-
logger.info("Migrations completed successfully!");
226209
} catch (error) {
227210
logger.error("Failed to run database migrations (pg):", error);
228-
// throw error;
229211
console.trace(error);
230212
}
231213
}

0 commit comments

Comments
 (0)