Added database connection retry

This commit is contained in:
thomashii@dukefirehawk.com 2022-07-11 14:15:02 +08:00
parent a5f4e4ff7a
commit f0a5e7c6fc
12 changed files with 128 additions and 23 deletions

View file

@ -13,5 +13,6 @@
},
"editor.codeActionsOnSave": {
"source.fixAll.markdownlint": true
}
},
"cmake.configureOnOpen": false
}

View file

@ -1,3 +1,5 @@
name: angel_orm_sqlite
environment:
sdk: ">=2.16.0 <3.0.0"
dependencies:
angel_orm: ^2.0.0-dev

30
docker/README.md Normal file
View file

@ -0,0 +1,30 @@
# Working with Docker
## Postgresql
### Starting the container
```bash
docker-compose -f docker-compose-pg.yml up
```
### Running psql
```bash
docker exec -it <container id> /bin/bash
psql --username postgres
```
### Create database, user and access
```psql
postgres=# create database orm_test;
postgres=# create user test with encrypted password 'test123';
postgres=# grant all privileges on database orm_test to test;
```
## MariaDB
## MySQL
## Redis

View file

@ -0,0 +1,21 @@
version: "3.8"
services:
pgdb:
image: postgres:latest
restart: always
ports:
- "5432:5432"
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
volumes:
- "db:/var/lib/postgresql/data"
networks:
- webnet
volumes:
db:
driver: local
networks:
webnet:

View file

@ -11,8 +11,8 @@ dependencies:
args: ^2.1.0
charcode: ^1.2.0
postgres: ^2.4.0
mysql_client: ^0.0.15
mysql1: ^0.19.0
mysql_client: ^0.0.24
mysql1: ^0.20.0
logging: ^1.0.0
dev_dependencies:
lints: ^2.0.0

View file

@ -8,8 +8,8 @@ environment:
dependencies:
angel3_orm: ^6.0.0
logging: ^1.0.0
mysql1: ^0.19.0
mysql_client: ^0.0.15
mysql1: ^0.20.0
mysql_client: ^0.0.24
optional: ^6.0.0
dev_dependencies:
angel3_orm_generator: ^6.0.0

View file

@ -3,6 +3,7 @@
## 6.0.1
* Upgraded to `lints` 2.x.x
* Fixed #71. Create a new database connection and retry.
## 6.0.0

View file

@ -7,7 +7,7 @@ import 'package:postgres/postgres.dart';
/// A [QueryExecutor] that queries a PostgreSQL database.
class PostgreSqlExecutor extends QueryExecutor {
final PostgreSQLExecutionContext _connection;
PostgreSQLExecutionContext _connection;
/// An optional [Logger] to print information to. A default logger will be used
/// if not set
@ -57,7 +57,43 @@ class PostgreSqlExecutor extends QueryExecutor {
}
});
return _connection.query(query, substitutionValues: param);
return _connection
.query(query, substitutionValues: param)
.catchError((err) async {
logger.warning(err);
if (err is PostgreSQLException) {
// This is a hack to detect broken db connection
bool brokenConnection =
err.message?.contains("connection is not open") ?? false;
if (brokenConnection) {
if (_connection is PostgreSQLConnection) {
// Open a new db connection
var currentConnection = _connection as PostgreSQLConnection;
currentConnection.close();
logger.warning(
"A broken database connection is detected. Creating a new database connection.");
var conn = _createNewConnection(currentConnection);
await conn.open();
_connection = conn;
// Retry the query with the new db connection
return _connection.query(query, substitutionValues: param);
}
}
}
throw err;
});
}
// Create a new database connection from an existing connection
PostgreSQLConnection _createNewConnection(PostgreSQLConnection conn) {
return PostgreSQLConnection(conn.host, conn.port, conn.databaseName,
username: conn.username,
password: conn.password,
useSSL: conn.useSSL,
timeZone: conn.timeZone,
timeoutInSeconds: conn.timeoutInSeconds);
}
@override

View file

@ -0,0 +1,14 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
declare module 'angel3_orm_test' {
interface Boat {
id?: string;
created_at?: any;
updated_at?: any;
make?: string;
description?: string;
family_friendly?: boolean;
recalled_at?: any;
price?: number;
width?: number;
}
}

View file

@ -5,24 +5,24 @@ import 'package:optional/optional.dart';
part 'boat.g.dart';
@serializable
@Serializable(serializers: Serializers.all)
@orm
abstract class _Boat extends Model {
@SerializableField(defaultValue: '')
@Column(defaultValue: '')
String get make;
@SerializableField(defaultValue: 'none')
@Column(defaultValue: 'none')
String get description;
@SerializableField(defaultValue: false)
@Column(defaultValue: false)
bool get familyFriendly;
//@SerializableField(defaultValue: '1970-01-01 00:00:00')
DateTime get recalledAt;
@SerializableField(defaultValue: 0.0)
@Column(defaultValue: 0.0)
double get price;
@SerializableField(defaultValue: 0)
@Column(defaultValue: 0)
int get width;
}

View file

@ -234,12 +234,12 @@ class Boat extends _Boat {
{this.id,
this.createdAt,
this.updatedAt,
this.make = '',
this.description = 'none',
this.familyFriendly = false,
required this.make,
required this.description,
required this.familyFriendly,
required this.recalledAt,
this.price = 0.0,
this.width = 0});
required this.price,
required this.width});
/// A unique identifier corresponding to this item.
@override
@ -372,16 +372,16 @@ class BoatSerializer extends Codec<Boat, Map> {
? (map['updated_at'] as DateTime)
: DateTime.parse(map['updated_at'].toString()))
: null,
make: map['make'] as String? ?? '',
description: map['description'] as String? ?? 'none',
familyFriendly: map['family_friendly'] as bool? ?? false,
make: map['make'] as String,
description: map['description'] as String,
familyFriendly: map['family_friendly'] as bool,
recalledAt: map['recalled_at'] != null
? (map['recalled_at'] is DateTime
? (map['recalled_at'] as DateTime)
: DateTime.parse(map['recalled_at'].toString()))
: DateTime.parse("1970-01-01 00:00:00"),
price: map['price'] as double? ?? 0.0,
width: map['width'] as int? ?? 0);
price: map['price'] as double,
width: map['width'] as int);
}
static Map<String, dynamic> toMap(_Boat? model) {