s3db.js 9.1.0 → 9.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/PLUGINS.md +871 -13
- package/README.md +31 -2
- package/dist/s3db.cjs.js +3867 -1615
- package/dist/s3db.cjs.js.map +1 -1
- package/dist/s3db.es.js +3870 -1621
- package/dist/s3db.es.js.map +1 -1
- package/package.json +5 -5
- package/src/concerns/async-event-emitter.js +46 -0
- package/src/database.class.js +23 -0
- package/src/plugins/backup/base-backup-driver.class.js +119 -0
- package/src/plugins/backup/filesystem-backup-driver.class.js +254 -0
- package/src/plugins/backup/index.js +85 -0
- package/src/plugins/backup/multi-backup-driver.class.js +304 -0
- package/src/plugins/backup/s3-backup-driver.class.js +313 -0
- package/src/plugins/backup.plugin.js +664 -0
- package/src/plugins/backup.plugin.js.backup +1026 -0
- package/src/plugins/cache/memory-cache.class.js +112 -3
- package/src/plugins/index.js +3 -0
- package/src/plugins/scheduler.plugin.js +833 -0
- package/src/plugins/state-machine.plugin.js +543 -0
- package/src/resource.class.js +9 -6
package/PLUGINS.md
CHANGED
|
@@ -18,6 +18,9 @@
|
|
|
18
18
|
- [📊 Metrics Plugin](#-metrics-plugin)
|
|
19
19
|
- [🔄 Replicator Plugin](#-replicator-plugin)
|
|
20
20
|
- [📬 Queue Consumer Plugin](#-queue-consumer-plugin)
|
|
21
|
+
- [🤖 State Machine Plugin](#-state-machine-plugin)
|
|
22
|
+
- [💾 Backup Plugin](#-backup-plugin)
|
|
23
|
+
- [⏰ Scheduler Plugin](#-scheduler-plugin)
|
|
21
24
|
- [🔧 Plugin Development](#-plugin-development)
|
|
22
25
|
- [💡 Plugin Combinations](#-plugin-combinations)
|
|
23
26
|
- [🎯 Best Practices](#-best-practices)
|
|
@@ -26,22 +29,68 @@
|
|
|
26
29
|
|
|
27
30
|
## 🚀 Getting Started with Plugins
|
|
28
31
|
|
|
29
|
-
Plugins extend s3db.js with additional functionality
|
|
32
|
+
Plugins extend s3db.js with additional functionality using a **driver-based architecture**. They can be used individually or combined for powerful workflows.
|
|
33
|
+
|
|
34
|
+
### Plugin Architecture
|
|
35
|
+
|
|
36
|
+
Most s3db.js plugins follow a **driver pattern** where you specify:
|
|
37
|
+
- **`driver`**: The storage/connection type (`filesystem`, `s3`, `multi`, etc.)
|
|
38
|
+
- **`config`**: Driver-specific configuration options
|
|
39
|
+
- **Plugin options**: Global settings that apply across drivers
|
|
30
40
|
|
|
31
41
|
### Basic Plugin Usage
|
|
32
42
|
|
|
33
43
|
```javascript
|
|
34
|
-
import { S3db, CachePlugin, CostsPlugin } from 's3db.js';
|
|
44
|
+
import { S3db, CachePlugin, BackupPlugin, CostsPlugin } from 's3db.js';
|
|
35
45
|
|
|
36
46
|
const s3db = new S3db({
|
|
37
|
-
connectionString: "s3://ACCESS_KEY:SECRET_KEY@BUCKET_NAME/databases/myapp"
|
|
38
|
-
plugins: [
|
|
39
|
-
new CachePlugin(),
|
|
40
|
-
CostsPlugin // Some plugins are static objects
|
|
41
|
-
]
|
|
47
|
+
connectionString: "s3://ACCESS_KEY:SECRET_KEY@BUCKET_NAME/databases/myapp"
|
|
42
48
|
});
|
|
43
49
|
|
|
44
50
|
await s3db.connect();
|
|
51
|
+
|
|
52
|
+
// Driver-based plugins (most common)
|
|
53
|
+
await s3db.usePlugin(new CachePlugin({
|
|
54
|
+
driver: 'memory',
|
|
55
|
+
config: { maxSize: 1000 }
|
|
56
|
+
}));
|
|
57
|
+
|
|
58
|
+
await s3db.usePlugin(new BackupPlugin({
|
|
59
|
+
driver: 'filesystem',
|
|
60
|
+
config: { path: './backups/{date}/' }
|
|
61
|
+
}));
|
|
62
|
+
|
|
63
|
+
// Static utility plugins
|
|
64
|
+
await s3db.usePlugin(CostsPlugin);
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Driver-Based Configuration Pattern
|
|
68
|
+
|
|
69
|
+
```javascript
|
|
70
|
+
// Single driver example
|
|
71
|
+
new SomePlugin({
|
|
72
|
+
driver: 'driverType',
|
|
73
|
+
config: {
|
|
74
|
+
// Driver-specific options
|
|
75
|
+
option1: 'value1',
|
|
76
|
+
option2: 'value2'
|
|
77
|
+
},
|
|
78
|
+
// Global plugin options
|
|
79
|
+
verbose: true,
|
|
80
|
+
timeout: 30000
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// Multi-driver example
|
|
84
|
+
new SomePlugin({
|
|
85
|
+
driver: 'multi',
|
|
86
|
+
config: {
|
|
87
|
+
strategy: 'all',
|
|
88
|
+
destinations: [
|
|
89
|
+
{ driver: 'driver1', config: {...} },
|
|
90
|
+
{ driver: 'driver2', config: {...} }
|
|
91
|
+
]
|
|
92
|
+
}
|
|
93
|
+
});
|
|
45
94
|
```
|
|
46
95
|
|
|
47
96
|
### Plugin Types
|
|
@@ -57,24 +106,72 @@ await s3db.connect();
|
|
|
57
106
|
|
|
58
107
|
## 💾 Cache Plugin
|
|
59
108
|
|
|
60
|
-
Intelligent caching
|
|
109
|
+
**Driver-Based Caching System** - Intelligent caching that reduces S3 API calls and improves performance using configurable storage drivers.
|
|
61
110
|
|
|
62
|
-
|
|
111
|
+
> 🏎️ **Performance**: Dramatically reduces S3 costs and latency by caching frequently accessed data.
|
|
112
|
+
|
|
113
|
+
### 🚀 Quick Start
|
|
63
114
|
|
|
115
|
+
#### Memory Driver (Fast & Temporary)
|
|
64
116
|
```javascript
|
|
65
117
|
import { S3db, CachePlugin } from 's3db.js';
|
|
66
118
|
|
|
67
119
|
const s3db = new S3db({
|
|
68
120
|
connectionString: "s3://ACCESS_KEY:SECRET_KEY@BUCKET_NAME/databases/myapp",
|
|
69
|
-
plugins: [
|
|
121
|
+
plugins: [
|
|
122
|
+
new CachePlugin({
|
|
123
|
+
driver: 'memory',
|
|
124
|
+
ttl: 300000, // 5 minutes
|
|
125
|
+
maxSize: 1000, // Max 1000 items
|
|
126
|
+
config: {
|
|
127
|
+
evictionPolicy: 'lru',
|
|
128
|
+
enableStats: true
|
|
129
|
+
}
|
|
130
|
+
})
|
|
131
|
+
]
|
|
70
132
|
});
|
|
71
133
|
|
|
72
134
|
await s3db.connect();
|
|
73
135
|
|
|
74
|
-
// Cache
|
|
136
|
+
// Cache automatically intercepts read operations
|
|
75
137
|
const users = s3db.resource('users');
|
|
76
|
-
await users.count(); // Cached for
|
|
77
|
-
await users.list(); // Cached result
|
|
138
|
+
await users.count(); // ⚡ Cached for 5 minutes
|
|
139
|
+
await users.list(); // ⚡ Cached result
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
#### S3 Driver (Persistent & Shared)
|
|
143
|
+
```javascript
|
|
144
|
+
const s3db = new S3db({
|
|
145
|
+
connectionString: "s3://ACCESS_KEY:SECRET_KEY@BUCKET_NAME/databases/myapp",
|
|
146
|
+
plugins: [
|
|
147
|
+
new CachePlugin({
|
|
148
|
+
driver: 's3',
|
|
149
|
+
ttl: 1800000, // 30 minutes
|
|
150
|
+
config: {
|
|
151
|
+
bucket: 'my-cache-bucket', // Optional: separate bucket
|
|
152
|
+
keyPrefix: 'cache/', // Cache key prefix
|
|
153
|
+
storageClass: 'STANDARD' // S3 storage class
|
|
154
|
+
}
|
|
155
|
+
})
|
|
156
|
+
]
|
|
157
|
+
});
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
#### Filesystem Driver (Local & Fast)
|
|
161
|
+
```javascript
|
|
162
|
+
const s3db = new S3db({
|
|
163
|
+
connectionString: "s3://ACCESS_KEY:SECRET_KEY@BUCKET_NAME/databases/myapp",
|
|
164
|
+
plugins: [
|
|
165
|
+
new CachePlugin({
|
|
166
|
+
driver: 'filesystem',
|
|
167
|
+
config: {
|
|
168
|
+
path: './cache',
|
|
169
|
+
partitionAware: true,
|
|
170
|
+
partitionStrategy: 'hierarchical'
|
|
171
|
+
}
|
|
172
|
+
})
|
|
173
|
+
]
|
|
174
|
+
});
|
|
78
175
|
```
|
|
79
176
|
|
|
80
177
|
### ⚙️ Configuration Parameters
|
|
@@ -4143,6 +4240,758 @@ const s3db = new S3db({
|
|
|
4143
4240
|
|
|
4144
4241
|
---
|
|
4145
4242
|
|
|
4243
|
+
## 🤖 State Machine Plugin
|
|
4244
|
+
|
|
4245
|
+
Finite state machine capabilities for managing complex workflows and business processes with well-defined states and transitions.
|
|
4246
|
+
|
|
4247
|
+
### ⚡ Quick Start
|
|
4248
|
+
|
|
4249
|
+
```javascript
|
|
4250
|
+
import { S3db, StateMachinePlugin } from 's3db.js';
|
|
4251
|
+
|
|
4252
|
+
const s3db = new S3db({
|
|
4253
|
+
connectionString: "s3://ACCESS_KEY:SECRET_KEY@BUCKET_NAME/databases/myapp",
|
|
4254
|
+
plugins: [
|
|
4255
|
+
new StateMachinePlugin({
|
|
4256
|
+
stateMachines: {
|
|
4257
|
+
order_processing: {
|
|
4258
|
+
initialState: 'pending',
|
|
4259
|
+
states: {
|
|
4260
|
+
pending: {
|
|
4261
|
+
on: { CONFIRM: 'confirmed', CANCEL: 'cancelled' }
|
|
4262
|
+
},
|
|
4263
|
+
confirmed: {
|
|
4264
|
+
on: { PREPARE: 'preparing', CANCEL: 'cancelled' },
|
|
4265
|
+
entry: 'onConfirmed'
|
|
4266
|
+
},
|
|
4267
|
+
preparing: {
|
|
4268
|
+
on: { SHIP: 'shipped', CANCEL: 'cancelled' },
|
|
4269
|
+
guards: { SHIP: 'canShip' }
|
|
4270
|
+
},
|
|
4271
|
+
shipped: {
|
|
4272
|
+
on: { DELIVER: 'delivered', RETURN: 'returned' }
|
|
4273
|
+
},
|
|
4274
|
+
delivered: { type: 'final' },
|
|
4275
|
+
cancelled: { type: 'final' },
|
|
4276
|
+
returned: { type: 'final' }
|
|
4277
|
+
}
|
|
4278
|
+
}
|
|
4279
|
+
},
|
|
4280
|
+
actions: {
|
|
4281
|
+
onConfirmed: async (context, event, machine) => {
|
|
4282
|
+
console.log(`Order ${context.id} confirmed!`);
|
|
4283
|
+
return { action: 'confirmed', timestamp: new Date() };
|
|
4284
|
+
}
|
|
4285
|
+
},
|
|
4286
|
+
guards: {
|
|
4287
|
+
canShip: async (context, event, machine) => {
|
|
4288
|
+
const inventory = await machine.database.resource('inventory').get(context.productId);
|
|
4289
|
+
return inventory && inventory.quantity >= context.quantity;
|
|
4290
|
+
}
|
|
4291
|
+
}
|
|
4292
|
+
})
|
|
4293
|
+
]
|
|
4294
|
+
});
|
|
4295
|
+
|
|
4296
|
+
await s3db.connect();
|
|
4297
|
+
|
|
4298
|
+
// Initialize entity with state machine
|
|
4299
|
+
await s3db.plugins.stateMachine.initializeEntity('order_processing', 'order123');
|
|
4300
|
+
|
|
4301
|
+
// Send events to trigger transitions
|
|
4302
|
+
await s3db.plugins.stateMachine.send('order_processing', 'order123', 'CONFIRM', {
|
|
4303
|
+
id: 'order123',
|
|
4304
|
+
productId: 'prod1',
|
|
4305
|
+
quantity: 2
|
|
4306
|
+
});
|
|
4307
|
+
|
|
4308
|
+
// Get current state
|
|
4309
|
+
const state = await s3db.plugins.stateMachine.getState('order_processing', 'order123');
|
|
4310
|
+
console.log('Current state:', state); // 'confirmed'
|
|
4311
|
+
```
|
|
4312
|
+
|
|
4313
|
+
### ⚙️ Configuration Parameters
|
|
4314
|
+
|
|
4315
|
+
| Parameter | Type | Default | Description |
|
|
4316
|
+
|-----------|------|---------|-------------|
|
|
4317
|
+
| `stateMachines` | object | `{}` | State machine definitions |
|
|
4318
|
+
| `actions` | object | `{}` | Action functions for state entry/exit |
|
|
4319
|
+
| `guards` | object | `{}` | Guard functions for transition validation |
|
|
4320
|
+
| `persistTransitions` | boolean | `true` | Store transition history in database |
|
|
4321
|
+
| `transitionLogResource` | string | `'transitions'` | Resource name for transition log |
|
|
4322
|
+
| `stateResource` | string | `'entity_states'` | Resource name for current states |
|
|
4323
|
+
| `verbose` | boolean | `false` | Enable detailed logging |
|
|
4324
|
+
|
|
4325
|
+
### State Machine Definition Structure
|
|
4326
|
+
|
|
4327
|
+
```javascript
|
|
4328
|
+
stateMachines: {
|
|
4329
|
+
machine_name: {
|
|
4330
|
+
initialState: 'start_state',
|
|
4331
|
+
states: {
|
|
4332
|
+
state_name: {
|
|
4333
|
+
on: { EVENT_NAME: 'target_state' }, // Transitions
|
|
4334
|
+
entry: 'action_name', // Action on state entry
|
|
4335
|
+
exit: 'action_name', // Action on state exit
|
|
4336
|
+
guards: { EVENT_NAME: 'guard_name' }, // Transition guards
|
|
4337
|
+
meta: { custom: 'metadata' }, // Additional metadata
|
|
4338
|
+
type: 'final' // Mark as final state
|
|
4339
|
+
}
|
|
4340
|
+
}
|
|
4341
|
+
}
|
|
4342
|
+
}
|
|
4343
|
+
```
|
|
4344
|
+
|
|
4345
|
+
### API Methods
|
|
4346
|
+
|
|
4347
|
+
```javascript
|
|
4348
|
+
// Entity management
|
|
4349
|
+
await stateMachine.initializeEntity(machineId, entityId, context);
|
|
4350
|
+
const state = await stateMachine.getState(machineId, entityId);
|
|
4351
|
+
const result = await stateMachine.send(machineId, entityId, event, context);
|
|
4352
|
+
|
|
4353
|
+
// State information
|
|
4354
|
+
const events = stateMachine.getValidEvents(machineId, entityId);
|
|
4355
|
+
const definition = stateMachine.getMachineDefinition(machineId);
|
|
4356
|
+
const machines = stateMachine.getMachines();
|
|
4357
|
+
|
|
4358
|
+
// History and visualization
|
|
4359
|
+
const history = await stateMachine.getTransitionHistory(machineId, entityId);
|
|
4360
|
+
const dot = stateMachine.visualize(machineId); // Graphviz DOT format
|
|
4361
|
+
```
|
|
4362
|
+
|
|
4363
|
+
### Events
|
|
4364
|
+
|
|
4365
|
+
```javascript
|
|
4366
|
+
stateMachine.on('initialized', ({ machines }) => {
|
|
4367
|
+
console.log('Initialized machines:', machines);
|
|
4368
|
+
});
|
|
4369
|
+
|
|
4370
|
+
stateMachine.on('transition', ({ machineId, entityId, from, to, event, context }) => {
|
|
4371
|
+
console.log(`${entityId}: ${from} → ${to} via ${event}`);
|
|
4372
|
+
});
|
|
4373
|
+
|
|
4374
|
+
stateMachine.on('action_error', ({ actionName, error, machineId, entityId }) => {
|
|
4375
|
+
console.error(`Action ${actionName} failed:`, error);
|
|
4376
|
+
});
|
|
4377
|
+
```
|
|
4378
|
+
|
|
4379
|
+
---
|
|
4380
|
+
|
|
4381
|
+
## 💾 Backup Plugin
|
|
4382
|
+
|
|
4383
|
+
**Driver-Based Backup System** - Comprehensive database backup and restore capabilities with configurable drivers, compression, encryption, and retention policies.
|
|
4384
|
+
|
|
4385
|
+
> ⚡ **NEW**: Driver-based architecture supports filesystem, S3, and multi-destination backups with flexible strategies.
|
|
4386
|
+
|
|
4387
|
+
### 🚀 Quick Start
|
|
4388
|
+
|
|
4389
|
+
#### Single Driver (Filesystem)
|
|
4390
|
+
```javascript
|
|
4391
|
+
import { S3db, BackupPlugin } from 's3db.js';
|
|
4392
|
+
|
|
4393
|
+
const s3db = new S3db({
|
|
4394
|
+
connectionString: "s3://ACCESS_KEY:SECRET_KEY@BUCKET_NAME/databases/myapp"
|
|
4395
|
+
});
|
|
4396
|
+
|
|
4397
|
+
await s3db.connect();
|
|
4398
|
+
|
|
4399
|
+
// Install backup plugin with filesystem driver
|
|
4400
|
+
const backupPlugin = new BackupPlugin({
|
|
4401
|
+
driver: 'filesystem',
|
|
4402
|
+
config: {
|
|
4403
|
+
path: './backups/{date}/',
|
|
4404
|
+
compression: 'gzip'
|
|
4405
|
+
},
|
|
4406
|
+
retention: {
|
|
4407
|
+
daily: 7,
|
|
4408
|
+
weekly: 4,
|
|
4409
|
+
monthly: 12
|
|
4410
|
+
}
|
|
4411
|
+
});
|
|
4412
|
+
|
|
4413
|
+
await s3db.usePlugin(backupPlugin);
|
|
4414
|
+
|
|
4415
|
+
// Create backups
|
|
4416
|
+
const fullBackup = await backupPlugin.backup('full');
|
|
4417
|
+
console.log('Backup ID:', fullBackup.id);
|
|
4418
|
+
|
|
4419
|
+
// List and restore
|
|
4420
|
+
const backups = await backupPlugin.listBackups();
|
|
4421
|
+
await backupPlugin.restore(fullBackup.id);
|
|
4422
|
+
```
|
|
4423
|
+
|
|
4424
|
+
#### Single Driver (S3)
|
|
4425
|
+
```javascript
|
|
4426
|
+
const backupPlugin = new BackupPlugin({
|
|
4427
|
+
driver: 's3',
|
|
4428
|
+
config: {
|
|
4429
|
+
bucket: 'my-backup-bucket',
|
|
4430
|
+
path: 'database/{date}/',
|
|
4431
|
+
storageClass: 'STANDARD_IA',
|
|
4432
|
+
serverSideEncryption: 'AES256'
|
|
4433
|
+
},
|
|
4434
|
+
compression: 'gzip',
|
|
4435
|
+
verification: true
|
|
4436
|
+
});
|
|
4437
|
+
```
|
|
4438
|
+
|
|
4439
|
+
#### Multi-Driver (Multiple Destinations)
|
|
4440
|
+
```javascript
|
|
4441
|
+
const backupPlugin = new BackupPlugin({
|
|
4442
|
+
driver: 'multi',
|
|
4443
|
+
config: {
|
|
4444
|
+
strategy: 'all', // 'all', 'any', 'priority'
|
|
4445
|
+
destinations: [
|
|
4446
|
+
{
|
|
4447
|
+
driver: 'filesystem',
|
|
4448
|
+
config: { path: '/local/backups/{date}/' }
|
|
4449
|
+
},
|
|
4450
|
+
{
|
|
4451
|
+
driver: 's3',
|
|
4452
|
+
config: {
|
|
4453
|
+
bucket: 'remote-backups',
|
|
4454
|
+
storageClass: 'GLACIER'
|
|
4455
|
+
}
|
|
4456
|
+
}
|
|
4457
|
+
]
|
|
4458
|
+
}
|
|
4459
|
+
});
|
|
4460
|
+
```
|
|
4461
|
+
|
|
4462
|
+
### 🎯 Driver Types
|
|
4463
|
+
|
|
4464
|
+
#### 📁 Filesystem Driver
|
|
4465
|
+
**Perfect for**: Local backups, network storage, development
|
|
4466
|
+
|
|
4467
|
+
```javascript
|
|
4468
|
+
{
|
|
4469
|
+
driver: 'filesystem',
|
|
4470
|
+
config: {
|
|
4471
|
+
path: '/backups/{date}/', // Template path with variables
|
|
4472
|
+
permissions: 0o644, // File permissions
|
|
4473
|
+
directoryPermissions: 0o755 // Directory permissions
|
|
4474
|
+
}
|
|
4475
|
+
}
|
|
4476
|
+
```
|
|
4477
|
+
|
|
4478
|
+
**Path Templates:**
|
|
4479
|
+
- `{date}` → `2024-03-15`
|
|
4480
|
+
- `{time}` → `14-30-45`
|
|
4481
|
+
- `{year}` → `2024`
|
|
4482
|
+
- `{month}` → `03`
|
|
4483
|
+
- `{day}` → `15`
|
|
4484
|
+
- `{backupId}` → `full-2024-03-15T14-30-45-abc123`
|
|
4485
|
+
- `{type}` → `full` | `incremental`
|
|
4486
|
+
|
|
4487
|
+
#### ☁️ S3 Driver
|
|
4488
|
+
**Perfect for**: Cloud backups, long-term storage, disaster recovery
|
|
4489
|
+
|
|
4490
|
+
```javascript
|
|
4491
|
+
{
|
|
4492
|
+
driver: 's3',
|
|
4493
|
+
config: {
|
|
4494
|
+
bucket: 'my-backup-bucket', // S3 bucket (optional, uses database bucket)
|
|
4495
|
+
path: 'backups/{date}/', // S3 key prefix with templates
|
|
4496
|
+
storageClass: 'STANDARD_IA', // S3 storage class
|
|
4497
|
+
serverSideEncryption: 'AES256', // Server-side encryption
|
|
4498
|
+
client: customS3Client // Custom S3 client (optional)
|
|
4499
|
+
}
|
|
4500
|
+
}
|
|
4501
|
+
```
|
|
4502
|
+
|
|
4503
|
+
**Storage Classes:** `STANDARD`, `STANDARD_IA`, `ONEZONE_IA`, `REDUCED_REDUNDANCY`, `GLACIER`, `DEEP_ARCHIVE`
|
|
4504
|
+
|
|
4505
|
+
#### 🔄 Multi Driver
|
|
4506
|
+
**Perfect for**: Redundancy, hybrid storage, complex backup strategies
|
|
4507
|
+
|
|
4508
|
+
```javascript
|
|
4509
|
+
{
|
|
4510
|
+
driver: 'multi',
|
|
4511
|
+
config: {
|
|
4512
|
+
strategy: 'all', // Backup strategy
|
|
4513
|
+
concurrency: 3, // Max concurrent uploads
|
|
4514
|
+
destinations: [
|
|
4515
|
+
{ driver: 'filesystem', config: {...} },
|
|
4516
|
+
{ driver: 's3', config: {...} }
|
|
4517
|
+
]
|
|
4518
|
+
}
|
|
4519
|
+
}
|
|
4520
|
+
```
|
|
4521
|
+
|
|
4522
|
+
**Strategies:**
|
|
4523
|
+
- **`all`**: Upload to all destinations (fail if any fails)
|
|
4524
|
+
- **`any`**: Upload to all, succeed if at least one succeeds
|
|
4525
|
+
- **`priority`**: Try destinations in order, stop on first success
|
|
4526
|
+
|
|
4527
|
+
### 🔧 Configuration Parameters
|
|
4528
|
+
|
|
4529
|
+
| Parameter | Type | Default | Description |
|
|
4530
|
+
|-----------|------|---------|-------------|
|
|
4531
|
+
| **`driver`** | `string` | `'filesystem'` | Driver type: `filesystem`, `s3`, `multi` |
|
|
4532
|
+
| **`config`** | `object` | `{}` | Driver-specific configuration |
|
|
4533
|
+
| `retention` | `object` | `{}` | Retention policy (GFS rotation) |
|
|
4534
|
+
| `include` | `array` | `null` | Resources to include (null = all) |
|
|
4535
|
+
| `exclude` | `array` | `[]` | Resources to exclude |
|
|
4536
|
+
| `compression` | `string` | `'gzip'` | `'none'`, `'gzip'`, `'brotli'`, `'deflate'` |
|
|
4537
|
+
| `encryption` | `object` | `null` | Encryption configuration |
|
|
4538
|
+
| `verification` | `boolean` | `true` | Verify backup integrity |
|
|
4539
|
+
| `tempDir` | `string` | `'./tmp/backups'` | Temporary working directory |
|
|
4540
|
+
| `verbose` | `boolean` | `false` | Enable detailed logging |
|
|
4541
|
+
|
|
4542
|
+
### 🎛️ Backup Types & Operations
|
|
4543
|
+
|
|
4544
|
+
```javascript
|
|
4545
|
+
// Full backup - complete database snapshot
|
|
4546
|
+
const fullBackup = await backupPlugin.backup('full');
|
|
4547
|
+
console.log(`✓ Full backup: ${fullBackup.id} (${fullBackup.size} bytes)`);
|
|
4548
|
+
|
|
4549
|
+
// Incremental backup - changes since last backup
|
|
4550
|
+
const incrementalBackup = await backupPlugin.backup('incremental');
|
|
4551
|
+
|
|
4552
|
+
// Selective backup - specific resources only
|
|
4553
|
+
const selectiveBackup = await backupPlugin.backup('full', {
|
|
4554
|
+
resources: ['users', 'posts']
|
|
4555
|
+
});
|
|
4556
|
+
|
|
4557
|
+
// Custom backup type
|
|
4558
|
+
const customBackup = await backupPlugin.backup('weekly-snapshot');
|
|
4559
|
+
```
|
|
4560
|
+
|
|
4561
|
+
### 📋 Backup Management
|
|
4562
|
+
|
|
4563
|
+
```javascript
|
|
4564
|
+
// List all backups
|
|
4565
|
+
const allBackups = await backupPlugin.listBackups();
|
|
4566
|
+
|
|
4567
|
+
// List with filters
|
|
4568
|
+
const recentBackups = await backupPlugin.listBackups({
|
|
4569
|
+
limit: 10,
|
|
4570
|
+
prefix: 'full-2024'
|
|
4571
|
+
});
|
|
4572
|
+
|
|
4573
|
+
// Get backup status
|
|
4574
|
+
const status = await backupPlugin.getBackupStatus(backupId);
|
|
4575
|
+
console.log(`Status: ${status.status}, Size: ${status.size}`);
|
|
4576
|
+
|
|
4577
|
+
// Restore operations
|
|
4578
|
+
await backupPlugin.restore(backupId); // Full restore
|
|
4579
|
+
await backupPlugin.restore(backupId, { overwrite: true }); // Overwrite existing
|
|
4580
|
+
await backupPlugin.restore(backupId, {
|
|
4581
|
+
resources: ['users']
|
|
4582
|
+
}); // Selective restore
|
|
4583
|
+
```
|
|
4584
|
+
|
|
4585
|
+
### 🔄 Legacy Format Support
|
|
4586
|
+
|
|
4587
|
+
The plugin automatically converts legacy `destinations` format:
|
|
4588
|
+
|
|
4589
|
+
```javascript
|
|
4590
|
+
// ❌ Old format (still works)
|
|
4591
|
+
new BackupPlugin({
|
|
4592
|
+
destinations: [
|
|
4593
|
+
{ type: 'filesystem', path: '/backups/' }
|
|
4594
|
+
]
|
|
4595
|
+
});
|
|
4596
|
+
|
|
4597
|
+
// ✅ Automatically converted to:
|
|
4598
|
+
// driver: 'multi'
|
|
4599
|
+
// config: { destinations: [{ driver: 'filesystem', config: { path: '/backups/' } }] }
|
|
4600
|
+
```
|
|
4601
|
+
|
|
4602
|
+
### 📊 Retention Policies (GFS)
|
|
4603
|
+
|
|
4604
|
+
Grandfather-Father-Son rotation keeps backups efficiently:
|
|
4605
|
+
|
|
4606
|
+
```javascript
|
|
4607
|
+
retention: {
|
|
4608
|
+
daily: 7, // Keep 7 daily backups
|
|
4609
|
+
weekly: 4, // Keep 4 weekly backups
|
|
4610
|
+
monthly: 12, // Keep 12 monthly backups
|
|
4611
|
+
yearly: 3 // Keep 3 yearly backups
|
|
4612
|
+
}
|
|
4613
|
+
```
|
|
4614
|
+
|
|
4615
|
+
### 🎣 Hooks & Events
|
|
4616
|
+
|
|
4617
|
+
```javascript
|
|
4618
|
+
const backupPlugin = new BackupPlugin({
|
|
4619
|
+
driver: 'filesystem',
|
|
4620
|
+
config: { path: './backups/' },
|
|
4621
|
+
|
|
4622
|
+
// Lifecycle hooks
|
|
4623
|
+
onBackupStart: async (type, { backupId }) => {
|
|
4624
|
+
console.log(`🚀 Starting ${type} backup: ${backupId}`);
|
|
4625
|
+
await notifySlack(`Backup ${backupId} started`);
|
|
4626
|
+
},
|
|
4627
|
+
|
|
4628
|
+
onBackupComplete: async (type, stats) => {
|
|
4629
|
+
console.log(`✅ ${type} backup completed:`, {
|
|
4630
|
+
id: stats.backupId,
|
|
4631
|
+
size: `${Math.round(stats.size / 1024)}KB`,
|
|
4632
|
+
duration: `${stats.duration}ms`,
|
|
4633
|
+
destinations: stats.driverInfo
|
|
4634
|
+
});
|
|
4635
|
+
},
|
|
4636
|
+
|
|
4637
|
+
onBackupError: async (type, { backupId, error }) => {
|
|
4638
|
+
console.error(`❌ Backup ${backupId} failed:`, error.message);
|
|
4639
|
+
await alertOps(error);
|
|
4640
|
+
}
|
|
4641
|
+
});
|
|
4642
|
+
|
|
4643
|
+
// Event listeners
|
|
4644
|
+
backupPlugin.on('backup_start', ({ id, type }) => {
|
|
4645
|
+
updateDashboard(`Backup ${id} started`);
|
|
4646
|
+
});
|
|
4647
|
+
|
|
4648
|
+
backupPlugin.on('backup_complete', ({ id, type, size, duration }) => {
|
|
4649
|
+
metrics.record('backup.completed', { type, size, duration });
|
|
4650
|
+
});
|
|
4651
|
+
|
|
4652
|
+
backupPlugin.on('restore_complete', ({ id, restored }) => {
|
|
4653
|
+
console.log(`Restored ${restored.length} resources from ${id}`);
|
|
4654
|
+
});
|
|
4655
|
+
```
|
|
4656
|
+
|
|
4657
|
+
### 🔒 Advanced Security
|
|
4658
|
+
|
|
4659
|
+
```javascript
|
|
4660
|
+
const secureBackupPlugin = new BackupPlugin({
|
|
4661
|
+
driver: 's3',
|
|
4662
|
+
config: {
|
|
4663
|
+
bucket: 'secure-backups',
|
|
4664
|
+
storageClass: 'STANDARD_IA',
|
|
4665
|
+
serverSideEncryption: 'aws:kms',
|
|
4666
|
+
kmsKeyId: 'arn:aws:kms:region:account:key/key-id'
|
|
4667
|
+
},
|
|
4668
|
+
|
|
4669
|
+
// Client-side encryption (before upload)
|
|
4670
|
+
encryption: {
|
|
4671
|
+
algorithm: 'AES-256-GCM',
|
|
4672
|
+
key: process.env.BACKUP_ENCRYPTION_KEY,
|
|
4673
|
+
keyDerivation: {
|
|
4674
|
+
algorithm: 'PBKDF2',
|
|
4675
|
+
iterations: 100000,
|
|
4676
|
+
salt: 'backup-salt-2024'
|
|
4677
|
+
}
|
|
4678
|
+
},
|
|
4679
|
+
|
|
4680
|
+
// Integrity verification
|
|
4681
|
+
verification: true,
|
|
4682
|
+
|
|
4683
|
+
// Compression for efficiency
|
|
4684
|
+
compression: 'gzip'
|
|
4685
|
+
});
|
|
4686
|
+
```
|
|
4687
|
+
|
|
4688
|
+
### 🚀 Production Examples
|
|
4689
|
+
|
|
4690
|
+
#### Enterprise Multi-Region Setup
|
|
4691
|
+
```javascript
|
|
4692
|
+
const enterpriseBackup = new BackupPlugin({
|
|
4693
|
+
driver: 'multi',
|
|
4694
|
+
config: {
|
|
4695
|
+
strategy: 'all',
|
|
4696
|
+
destinations: [
|
|
4697
|
+
{
|
|
4698
|
+
driver: 's3',
|
|
4699
|
+
config: {
|
|
4700
|
+
bucket: 'backups-us-east-1',
|
|
4701
|
+
path: 'production/{date}/',
|
|
4702
|
+
storageClass: 'STANDARD_IA'
|
|
4703
|
+
}
|
|
4704
|
+
},
|
|
4705
|
+
{
|
|
4706
|
+
driver: 's3',
|
|
4707
|
+
config: {
|
|
4708
|
+
bucket: 'backups-eu-west-1',
|
|
4709
|
+
path: 'production/{date}/',
|
|
4710
|
+
storageClass: 'STANDARD_IA'
|
|
4711
|
+
}
|
|
4712
|
+
},
|
|
4713
|
+
{
|
|
4714
|
+
driver: 'filesystem',
|
|
4715
|
+
config: {
|
|
4716
|
+
path: '/mnt/backup-nas/s3db/{date}/'
|
|
4717
|
+
}
|
|
4718
|
+
}
|
|
4719
|
+
]
|
|
4720
|
+
},
|
|
4721
|
+
retention: {
|
|
4722
|
+
daily: 30,
|
|
4723
|
+
weekly: 12,
|
|
4724
|
+
monthly: 24,
|
|
4725
|
+
yearly: 7
|
|
4726
|
+
},
|
|
4727
|
+
verification: true,
|
|
4728
|
+
compression: 'gzip'
|
|
4729
|
+
});
|
|
4730
|
+
```
|
|
4731
|
+
|
|
4732
|
+
#### Development Quick Backup
|
|
4733
|
+
```javascript
|
|
4734
|
+
const devBackup = new BackupPlugin({
|
|
4735
|
+
driver: 'filesystem',
|
|
4736
|
+
config: {
|
|
4737
|
+
path: './dev-backups/{date}/'
|
|
4738
|
+
},
|
|
4739
|
+
compression: 'none',
|
|
4740
|
+
verification: false,
|
|
4741
|
+
verbose: true,
|
|
4742
|
+
retention: { daily: 3 }
|
|
4743
|
+
});
|
|
4744
|
+
```
|
|
4745
|
+
|
|
4746
|
+
### 🎯 CLI Integration
|
|
4747
|
+
|
|
4748
|
+
The BackupPlugin works with s3db CLI commands:
|
|
4749
|
+
|
|
4750
|
+
```bash
|
|
4751
|
+
# Create backups
|
|
4752
|
+
s3db backup full --connection "s3://key:secret@bucket"
|
|
4753
|
+
s3db backup incremental --connection "s3://key:secret@bucket"
|
|
4754
|
+
|
|
4755
|
+
# List and status
|
|
4756
|
+
s3db backup --list --connection "s3://key:secret@bucket"
|
|
4757
|
+
s3db backup --status backup-id --connection "s3://key:secret@bucket"
|
|
4758
|
+
|
|
4759
|
+
# Restore operations
|
|
4760
|
+
s3db restore backup-id --connection "s3://key:secret@bucket"
|
|
4761
|
+
s3db restore backup-id --overwrite --connection "s3://key:secret@bucket"
|
|
4762
|
+
```
|
|
4763
|
+
|
|
4764
|
+
> **Note**: CLI requires the BackupPlugin to be installed in the database instance.
|
|
4765
|
+
|
|
4766
|
+
### 🔍 Driver Information
|
|
4767
|
+
|
|
4768
|
+
```javascript
|
|
4769
|
+
// Get driver details
|
|
4770
|
+
const driverInfo = backupPlugin.driver.getStorageInfo();
|
|
4771
|
+
console.log('Driver type:', driverInfo.type);
|
|
4772
|
+
console.log('Configuration:', driverInfo.config);
|
|
4773
|
+
|
|
4774
|
+
// Multi-driver details
|
|
4775
|
+
if (driverInfo.type === 'multi') {
|
|
4776
|
+
console.log('Strategy:', driverInfo.strategy);
|
|
4777
|
+
driverInfo.destinations.forEach((dest, i) => {
|
|
4778
|
+
console.log(`Destination ${i}:`, dest.driver, dest.info);
|
|
4779
|
+
});
|
|
4780
|
+
}
|
|
4781
|
+
```
|
|
4782
|
+
|
|
4783
|
+
---
|
|
4784
|
+
|
|
4785
|
+
## ⏰ Scheduler Plugin
|
|
4786
|
+
|
|
4787
|
+
Robust job scheduling capabilities with cron expressions, retry logic, and comprehensive monitoring for automated tasks.
|
|
4788
|
+
|
|
4789
|
+
### ⚡ Quick Start
|
|
4790
|
+
|
|
4791
|
+
```javascript
|
|
4792
|
+
import { S3db, SchedulerPlugin } from 's3db.js';
|
|
4793
|
+
|
|
4794
|
+
const s3db = new S3db({
|
|
4795
|
+
connectionString: "s3://ACCESS_KEY:SECRET_KEY@BUCKET_NAME/databases/myapp",
|
|
4796
|
+
plugins: [
|
|
4797
|
+
new SchedulerPlugin({
|
|
4798
|
+
timezone: 'America/Sao_Paulo',
|
|
4799
|
+
jobs: {
|
|
4800
|
+
daily_cleanup: {
|
|
4801
|
+
schedule: '0 3 * * *', // 3 AM daily
|
|
4802
|
+
description: 'Clean up expired sessions',
|
|
4803
|
+
action: async (database, context) => {
|
|
4804
|
+
const expired = await database.resource('sessions').list({
|
|
4805
|
+
where: { expiresAt: { $lt: new Date() } }
|
|
4806
|
+
});
|
|
4807
|
+
|
|
4808
|
+
for (const session of expired) {
|
|
4809
|
+
await database.resource('sessions').delete(session.id);
|
|
4810
|
+
}
|
|
4811
|
+
|
|
4812
|
+
return { deleted: expired.length };
|
|
4813
|
+
},
|
|
4814
|
+
enabled: true,
|
|
4815
|
+
retries: 2,
|
|
4816
|
+
timeout: 30000
|
|
4817
|
+
},
|
|
4818
|
+
|
|
4819
|
+
hourly_metrics: {
|
|
4820
|
+
schedule: '@hourly',
|
|
4821
|
+
description: 'Collect system metrics',
|
|
4822
|
+
action: async (database) => {
|
|
4823
|
+
const metrics = {
|
|
4824
|
+
timestamp: new Date().toISOString(),
|
|
4825
|
+
memory: process.memoryUsage(),
|
|
4826
|
+
uptime: process.uptime()
|
|
4827
|
+
};
|
|
4828
|
+
|
|
4829
|
+
await database.resource('metrics').insert({
|
|
4830
|
+
id: `metrics_${Date.now()}`,
|
|
4831
|
+
...metrics
|
|
4832
|
+
});
|
|
4833
|
+
|
|
4834
|
+
return metrics;
|
|
4835
|
+
}
|
|
4836
|
+
}
|
|
4837
|
+
},
|
|
4838
|
+
onJobComplete: (jobName, result, duration) => {
|
|
4839
|
+
console.log(`Job ${jobName} completed in ${duration}ms`);
|
|
4840
|
+
}
|
|
4841
|
+
})
|
|
4842
|
+
]
|
|
4843
|
+
});
|
|
4844
|
+
|
|
4845
|
+
await s3db.connect();
|
|
4846
|
+
|
|
4847
|
+
// Jobs run automatically based on schedule
|
|
4848
|
+
// Manual execution
|
|
4849
|
+
await s3db.plugins.scheduler.runJob('daily_cleanup');
|
|
4850
|
+
|
|
4851
|
+
// Get job status
|
|
4852
|
+
const allJobs = s3db.plugins.scheduler.getAllJobsStatus();
|
|
4853
|
+
console.log('Scheduled jobs:', allJobs.length);
|
|
4854
|
+
```
|
|
4855
|
+
|
|
4856
|
+
### ⚙️ Configuration Parameters
|
|
4857
|
+
|
|
4858
|
+
| Parameter | Type | Default | Description |
|
|
4859
|
+
|-----------|------|---------|-------------|
|
|
4860
|
+
| `timezone` | string | `'UTC'` | IANA timezone identifier |
|
|
4861
|
+
| `jobs` | object | `{}` | Job definitions |
|
|
4862
|
+
| `defaultTimeout` | number | `60000` | Default job timeout (ms) |
|
|
4863
|
+
| `defaultRetries` | number | `1` | Default retry attempts |
|
|
4864
|
+
| `persistJobs` | boolean | `true` | Store job execution history |
|
|
4865
|
+
| `jobHistoryResource` | string | `'job_history'` | Resource for job history |
|
|
4866
|
+
| `onJobStart` | function | `null` | Callback when job starts |
|
|
4867
|
+
| `onJobComplete` | function | `null` | Callback when job completes |
|
|
4868
|
+
| `onJobError` | function | `null` | Callback when job fails |
|
|
4869
|
+
| `verbose` | boolean | `false` | Enable detailed logging |
|
|
4870
|
+
|
|
4871
|
+
### Job Configuration
|
|
4872
|
+
|
|
4873
|
+
```javascript
|
|
4874
|
+
jobs: {
|
|
4875
|
+
job_name: {
|
|
4876
|
+
schedule: '0 0 * * *', // Cron expression (required)
|
|
4877
|
+
description: 'Job description', // Human-readable description
|
|
4878
|
+
action: async (database, context, schedulerPlugin) => {
|
|
4879
|
+
// Job implementation (required)
|
|
4880
|
+
return { success: true };
|
|
4881
|
+
},
|
|
4882
|
+
enabled: true, // Enable/disable job
|
|
4883
|
+
retries: 2, // Retry attempts on failure
|
|
4884
|
+
timeout: 30000, // Timeout in milliseconds
|
|
4885
|
+
meta: { priority: 'high' } // Custom metadata
|
|
4886
|
+
}
|
|
4887
|
+
}
|
|
4888
|
+
```
|
|
4889
|
+
|
|
4890
|
+
### Cron Expressions
|
|
4891
|
+
|
|
4892
|
+
#### Standard Format
|
|
4893
|
+
```
|
|
4894
|
+
* * * * *
|
|
4895
|
+
│ │ │ │ │
|
|
4896
|
+
│ │ │ │ └─── Day of week (0-7, Sunday = 0 or 7)
|
|
4897
|
+
│ │ │ └───── Month (1-12)
|
|
4898
|
+
│ │ └─────── Day of month (1-31)
|
|
4899
|
+
│ └───────── Hour (0-23)
|
|
4900
|
+
└─────────── Minute (0-59)
|
|
4901
|
+
```
|
|
4902
|
+
|
|
4903
|
+
#### Examples
|
|
4904
|
+
```javascript
|
|
4905
|
+
'0 0 * * *' // Daily at midnight
|
|
4906
|
+
'0 9 * * MON' // Every Monday at 9 AM
|
|
4907
|
+
'*/15 * * * *' // Every 15 minutes
|
|
4908
|
+
'0 2 1 * *' // First day of month at 2 AM
|
|
4909
|
+
```
|
|
4910
|
+
|
|
4911
|
+
#### Shorthand Expressions
|
|
4912
|
+
```javascript
|
|
4913
|
+
'@yearly' // Once a year at midnight on January 1st
|
|
4914
|
+
'@monthly' // Once a month at midnight on the 1st
|
|
4915
|
+
'@weekly' // Once a week at midnight on Sunday
|
|
4916
|
+
'@daily' // Once a day at midnight
|
|
4917
|
+
'@hourly' // Once an hour at the beginning of the hour
|
|
4918
|
+
```
|
|
4919
|
+
|
|
4920
|
+
### API Methods
|
|
4921
|
+
|
|
4922
|
+
```javascript
|
|
4923
|
+
// Job execution
|
|
4924
|
+
const result = await scheduler.runJob(jobName, context);
|
|
4925
|
+
const stats = scheduler.getJobStatus(jobName);
|
|
4926
|
+
const allJobs = scheduler.getAllJobsStatus();
|
|
4927
|
+
|
|
4928
|
+
// Job management
|
|
4929
|
+
scheduler.enableJob(jobName);
|
|
4930
|
+
scheduler.disableJob(jobName);
|
|
4931
|
+
scheduler.addJob(jobName, jobConfig);
|
|
4932
|
+
scheduler.removeJob(jobName);
|
|
4933
|
+
|
|
4934
|
+
// History and monitoring
|
|
4935
|
+
const history = await scheduler.getJobHistory(jobName, { status: 'success', limit: 10 });
|
|
4936
|
+
const stats = scheduler.getJobStatistics(jobName);
|
|
4937
|
+
```
|
|
4938
|
+
|
|
4939
|
+
### Events
|
|
4940
|
+
|
|
4941
|
+
```javascript
|
|
4942
|
+
scheduler.on('job_start', ({ jobName, context }) => {
|
|
4943
|
+
console.log(`Job ${jobName} started`);
|
|
4944
|
+
});
|
|
4945
|
+
|
|
4946
|
+
scheduler.on('job_complete', ({ jobName, result, duration }) => {
|
|
4947
|
+
console.log(`Job ${jobName} completed in ${duration}ms`);
|
|
4948
|
+
});
|
|
4949
|
+
|
|
4950
|
+
scheduler.on('job_error', ({ jobName, error, retryCount }) => {
|
|
4951
|
+
console.error(`Job ${jobName} failed (attempt ${retryCount}):`, error);
|
|
4952
|
+
});
|
|
4953
|
+
|
|
4954
|
+
scheduler.on('job_enabled', ({ jobName }) => {
|
|
4955
|
+
console.log(`Job ${jobName} enabled`);
|
|
4956
|
+
});
|
|
4957
|
+
```
|
|
4958
|
+
|
|
4959
|
+
### Integration with Other Plugins
|
|
4960
|
+
|
|
4961
|
+
```javascript
|
|
4962
|
+
// Scheduled backups
|
|
4963
|
+
jobs: {
|
|
4964
|
+
daily_backup: {
|
|
4965
|
+
schedule: '0 1 * * *',
|
|
4966
|
+
action: async (database) => {
|
|
4967
|
+
const backup = database.getPlugin('BackupPlugin');
|
|
4968
|
+
return await backup.backup('full');
|
|
4969
|
+
}
|
|
4970
|
+
}
|
|
4971
|
+
}
|
|
4972
|
+
|
|
4973
|
+
// Process state machine entities
|
|
4974
|
+
jobs: {
|
|
4975
|
+
process_pending_orders: {
|
|
4976
|
+
schedule: '*/10 * * * *',
|
|
4977
|
+
action: async (database) => {
|
|
4978
|
+
const stateMachine = database.getPlugin('StateMachinePlugin');
|
|
4979
|
+
const orders = await database.resource('orders').list({
|
|
4980
|
+
where: { status: 'pending' }
|
|
4981
|
+
});
|
|
4982
|
+
|
|
4983
|
+
for (const order of orders) {
|
|
4984
|
+
await stateMachine.send('order_processing', order.id, 'AUTO_PROCESS');
|
|
4985
|
+
}
|
|
4986
|
+
|
|
4987
|
+
return { processed: orders.length };
|
|
4988
|
+
}
|
|
4989
|
+
}
|
|
4990
|
+
}
|
|
4991
|
+
```
|
|
4992
|
+
|
|
4993
|
+
---
|
|
4994
|
+
|
|
4146
4995
|
## 🎯 Best Practices
|
|
4147
4996
|
|
|
4148
4997
|
### Plugin Performance
|
|
@@ -4152,6 +5001,9 @@ const s3db = new S3db({
|
|
|
4152
5001
|
3. **Use appropriate sampling** for metrics collection
|
|
4153
5002
|
4. **Configure retention policies** for audit logs
|
|
4154
5003
|
5. **Test replicator connections** before deployment
|
|
5004
|
+
6. **Design efficient state machines** with minimal guards and actions
|
|
5005
|
+
7. **Schedule backups during low-traffic periods** to minimize impact
|
|
5006
|
+
8. **Use appropriate job timeouts** to prevent resource exhaustion
|
|
4155
5007
|
|
|
4156
5008
|
### Plugin Security
|
|
4157
5009
|
|
|
@@ -4160,6 +5012,9 @@ const s3db = new S3db({
|
|
|
4160
5012
|
3. **Use IAM roles** instead of access keys when possible
|
|
4161
5013
|
4. **Encrypt replication data** in transit and at rest
|
|
4162
5014
|
5. **Validate message sources** in queue consumers
|
|
5015
|
+
6. **Secure state machine actions** to prevent unauthorized transitions
|
|
5016
|
+
7. **Encrypt backup data** for sensitive databases
|
|
5017
|
+
8. **Restrict job execution permissions** to necessary resources only
|
|
4163
5018
|
|
|
4164
5019
|
### Plugin Monitoring
|
|
4165
5020
|
|
|
@@ -4168,6 +5023,9 @@ const s3db = new S3db({
|
|
|
4168
5023
|
3. **Track error rates** across all plugins
|
|
4169
5024
|
4. **Use structured logging** for debugging
|
|
4170
5025
|
5. **Implement circuit breakers** for external services
|
|
5026
|
+
6. **Monitor state machine transition rates** and error patterns
|
|
5027
|
+
7. **Track backup success rates** and storage usage
|
|
5028
|
+
8. **Alert on job failures** and execution delays
|
|
4171
5029
|
|
|
4172
5030
|
---
|
|
4173
5031
|
|