ghost 5.77.0 → 5.79.0
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/components/tryghost-adapter-cache-memory-ttl-5.79.0.tgz +0 -0
- package/components/tryghost-adapter-cache-redis-5.79.0.tgz +0 -0
- package/components/tryghost-adapter-manager-5.79.0.tgz +0 -0
- package/components/tryghost-announcement-bar-settings-5.79.0.tgz +0 -0
- package/components/tryghost-api-framework-5.79.0.tgz +0 -0
- package/components/tryghost-api-version-compatibility-service-5.79.0.tgz +0 -0
- package/components/tryghost-audience-feedback-5.79.0.tgz +0 -0
- package/components/tryghost-bookshelf-repository-5.79.0.tgz +0 -0
- package/components/tryghost-bootstrap-socket-5.79.0.tgz +0 -0
- package/components/tryghost-collections-5.79.0.tgz +0 -0
- package/components/tryghost-constants-5.79.0.tgz +0 -0
- package/components/tryghost-custom-theme-settings-service-5.79.0.tgz +0 -0
- package/components/{tryghost-data-generator-5.77.0.tgz → tryghost-data-generator-5.79.0.tgz} +0 -0
- package/components/tryghost-domain-events-5.79.0.tgz +0 -0
- package/components/tryghost-donations-5.79.0.tgz +0 -0
- package/components/tryghost-dynamic-routing-events-5.79.0.tgz +0 -0
- package/components/{tryghost-email-addresses-5.77.0.tgz → tryghost-email-addresses-5.79.0.tgz} +0 -0
- package/components/tryghost-email-analytics-provider-mailgun-5.79.0.tgz +0 -0
- package/components/tryghost-email-analytics-service-5.79.0.tgz +0 -0
- package/components/tryghost-email-content-generator-5.79.0.tgz +0 -0
- package/components/tryghost-email-events-5.79.0.tgz +0 -0
- package/components/tryghost-email-service-5.79.0.tgz +0 -0
- package/components/tryghost-email-suppression-list-5.79.0.tgz +0 -0
- package/components/tryghost-express-dynamic-redirects-5.79.0.tgz +0 -0
- package/components/tryghost-external-media-inliner-5.79.0.tgz +0 -0
- package/components/tryghost-extract-api-key-5.79.0.tgz +0 -0
- package/components/tryghost-html-to-plaintext-5.79.0.tgz +0 -0
- package/components/tryghost-i18n-5.79.0.tgz +0 -0
- package/components/tryghost-importer-handler-content-files-5.79.0.tgz +0 -0
- package/components/{tryghost-importer-revue-5.77.0.tgz → tryghost-importer-revue-5.79.0.tgz} +0 -0
- package/components/{tryghost-in-memory-repository-5.77.0.tgz → tryghost-in-memory-repository-5.79.0.tgz} +0 -0
- package/components/tryghost-job-manager-5.79.0.tgz +0 -0
- package/components/tryghost-link-redirects-5.79.0.tgz +0 -0
- package/components/tryghost-link-replacer-5.79.0.tgz +0 -0
- package/components/tryghost-link-tracking-5.79.0.tgz +0 -0
- package/components/{tryghost-magic-link-5.77.0.tgz → tryghost-magic-link-5.79.0.tgz} +0 -0
- package/components/tryghost-mail-events-5.79.0.tgz +0 -0
- package/components/tryghost-mailgun-client-5.79.0.tgz +0 -0
- package/components/tryghost-member-attribution-5.79.0.tgz +0 -0
- package/components/tryghost-member-events-5.79.0.tgz +0 -0
- package/components/tryghost-members-api-5.79.0.tgz +0 -0
- package/components/tryghost-members-csv-5.79.0.tgz +0 -0
- package/components/tryghost-members-events-service-5.79.0.tgz +0 -0
- package/components/{tryghost-members-importer-5.77.0.tgz → tryghost-members-importer-5.79.0.tgz} +0 -0
- package/components/tryghost-members-offers-5.79.0.tgz +0 -0
- package/components/tryghost-members-payments-5.79.0.tgz +0 -0
- package/components/tryghost-members-ssr-5.79.0.tgz +0 -0
- package/components/{tryghost-members-stripe-service-5.77.0.tgz → tryghost-members-stripe-service-5.79.0.tgz} +0 -0
- package/components/tryghost-mentions-email-report-5.79.0.tgz +0 -0
- package/components/tryghost-milestones-5.79.0.tgz +0 -0
- package/components/{tryghost-minifier-5.77.0.tgz → tryghost-minifier-5.79.0.tgz} +0 -0
- package/components/tryghost-model-to-domain-event-interceptor-5.79.0.tgz +0 -0
- package/components/tryghost-mw-api-version-mismatch-5.79.0.tgz +0 -0
- package/components/tryghost-mw-cache-control-5.79.0.tgz +0 -0
- package/components/tryghost-mw-error-handler-5.79.0.tgz +0 -0
- package/components/tryghost-mw-session-from-token-5.79.0.tgz +0 -0
- package/components/tryghost-mw-update-user-last-seen-5.79.0.tgz +0 -0
- package/components/tryghost-mw-version-match-5.79.0.tgz +0 -0
- package/components/tryghost-mw-vhost-5.79.0.tgz +0 -0
- package/components/tryghost-nql-filter-expansions-5.79.0.tgz +0 -0
- package/components/tryghost-oembed-service-5.79.0.tgz +0 -0
- package/components/tryghost-package-json-5.79.0.tgz +0 -0
- package/components/tryghost-post-events-5.79.0.tgz +0 -0
- package/components/tryghost-post-revisions-5.79.0.tgz +0 -0
- package/components/tryghost-posts-service-5.79.0.tgz +0 -0
- package/components/tryghost-recommendations-5.79.0.tgz +0 -0
- package/components/tryghost-referrers-5.79.0.tgz +0 -0
- package/components/tryghost-security-5.79.0.tgz +0 -0
- package/components/tryghost-session-service-5.79.0.tgz +0 -0
- package/components/tryghost-settings-path-manager-5.79.0.tgz +0 -0
- package/components/tryghost-slack-notifications-5.79.0.tgz +0 -0
- package/components/{tryghost-staff-service-5.77.0.tgz → tryghost-staff-service-5.79.0.tgz} +0 -0
- package/components/tryghost-stats-service-5.79.0.tgz +0 -0
- package/components/tryghost-tiers-5.79.0.tgz +0 -0
- package/components/tryghost-update-check-service-5.79.0.tgz +0 -0
- package/components/{tryghost-verification-trigger-5.77.0.tgz → tryghost-verification-trigger-5.79.0.tgz} +0 -0
- package/components/tryghost-version-notifications-data-service-5.79.0.tgz +0 -0
- package/components/tryghost-webmentions-5.79.0.tgz +0 -0
- package/core/boot.js +1 -9
- package/core/built/admin/assets/admin-x-demo/admin-x-demo.js +1 -1
- package/core/built/admin/assets/admin-x-demo/{index-eee22c84.mjs → index-0722d3aa.mjs} +3 -3
- package/core/built/admin/assets/admin-x-demo/{modals-e4b12fba.mjs → modals-969dbbd3.mjs} +2 -2
- package/core/built/admin/assets/admin-x-settings/{CodeEditorView-c3b34635.mjs → CodeEditorView-ca5a31fd.mjs} +2 -2
- package/core/built/admin/assets/admin-x-settings/admin-x-settings.js +1 -1
- package/core/built/admin/assets/admin-x-settings/{index-8808e054.mjs → index-60a33701.mjs} +2 -2
- package/core/built/admin/assets/admin-x-settings/{index-99bd65a2.mjs → index-f874baf8.mjs} +5 -4
- package/core/built/admin/assets/admin-x-settings/{modals-f491bd44.mjs → modals-7dbf838b.mjs} +3 -3
- package/core/built/admin/assets/{chunk.664.99d0951b803d7ec00d8b.js → chunk.160.f064da019dcb493ba212.js} +2737 -2737
- package/core/built/admin/assets/chunk.524.fe4143d694c7ab008a78.js +35 -0
- package/core/built/admin/assets/{chunk.178.09e01be47e7daa486981.js → chunk.92.812dc089b3ac289f0866.js} +4 -4
- package/core/built/admin/assets/{ghost-90accaf45b85c7bc55ca781472d27e8e.js → ghost-74787e16c2e5229de6164ddfe7426882.js} +18 -17
- package/core/built/admin/assets/koenig-lexical/koenig-lexical.js +5009 -4993
- package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +79 -79
- package/core/built/admin/index.html +4 -4
- package/core/server/data/db/ConnectionPoolInstrumentation.js +142 -0
- package/core/server/data/db/backup.js +7 -1
- package/core/server/data/db/connection.js +6 -0
- package/core/server/data/db/index.js +9 -0
- package/core/server/data/migrations/versions/5.79/2024-01-30-19-36-44-fix-discrepancy-in-free-tier-visibility.js +43 -0
- package/core/server/services/Users.js +6 -2
- package/core/shared/config/defaults.json +2 -1
- package/core/shared/labs.js +2 -2
- package/package.json +150 -151
- package/yarn.lock +351 -353
- package/components/tryghost-adapter-cache-memory-ttl-5.77.0.tgz +0 -0
- package/components/tryghost-adapter-cache-redis-5.77.0.tgz +0 -0
- package/components/tryghost-adapter-manager-5.77.0.tgz +0 -0
- package/components/tryghost-announcement-bar-settings-5.77.0.tgz +0 -0
- package/components/tryghost-api-framework-5.77.0.tgz +0 -0
- package/components/tryghost-api-version-compatibility-service-5.77.0.tgz +0 -0
- package/components/tryghost-audience-feedback-5.77.0.tgz +0 -0
- package/components/tryghost-bookshelf-repository-5.77.0.tgz +0 -0
- package/components/tryghost-bootstrap-socket-5.77.0.tgz +0 -0
- package/components/tryghost-collections-5.77.0.tgz +0 -0
- package/components/tryghost-constants-5.77.0.tgz +0 -0
- package/components/tryghost-custom-theme-settings-service-5.77.0.tgz +0 -0
- package/components/tryghost-domain-events-5.77.0.tgz +0 -0
- package/components/tryghost-donations-5.77.0.tgz +0 -0
- package/components/tryghost-dynamic-routing-events-5.77.0.tgz +0 -0
- package/components/tryghost-email-analytics-provider-mailgun-5.77.0.tgz +0 -0
- package/components/tryghost-email-analytics-service-5.77.0.tgz +0 -0
- package/components/tryghost-email-content-generator-5.77.0.tgz +0 -0
- package/components/tryghost-email-events-5.77.0.tgz +0 -0
- package/components/tryghost-email-service-5.77.0.tgz +0 -0
- package/components/tryghost-email-suppression-list-5.77.0.tgz +0 -0
- package/components/tryghost-express-dynamic-redirects-5.77.0.tgz +0 -0
- package/components/tryghost-external-media-inliner-5.77.0.tgz +0 -0
- package/components/tryghost-extract-api-key-5.77.0.tgz +0 -0
- package/components/tryghost-html-to-plaintext-5.77.0.tgz +0 -0
- package/components/tryghost-i18n-5.77.0.tgz +0 -0
- package/components/tryghost-importer-handler-content-files-5.77.0.tgz +0 -0
- package/components/tryghost-job-manager-5.77.0.tgz +0 -0
- package/components/tryghost-link-redirects-5.77.0.tgz +0 -0
- package/components/tryghost-link-replacer-5.77.0.tgz +0 -0
- package/components/tryghost-link-tracking-5.77.0.tgz +0 -0
- package/components/tryghost-mail-events-5.77.0.tgz +0 -0
- package/components/tryghost-mailgun-client-5.77.0.tgz +0 -0
- package/components/tryghost-member-attribution-5.77.0.tgz +0 -0
- package/components/tryghost-member-events-5.77.0.tgz +0 -0
- package/components/tryghost-members-api-5.77.0.tgz +0 -0
- package/components/tryghost-members-csv-5.77.0.tgz +0 -0
- package/components/tryghost-members-events-service-5.77.0.tgz +0 -0
- package/components/tryghost-members-offers-5.77.0.tgz +0 -0
- package/components/tryghost-members-payments-5.77.0.tgz +0 -0
- package/components/tryghost-members-ssr-5.77.0.tgz +0 -0
- package/components/tryghost-mentions-email-report-5.77.0.tgz +0 -0
- package/components/tryghost-milestones-5.77.0.tgz +0 -0
- package/components/tryghost-model-to-domain-event-interceptor-5.77.0.tgz +0 -0
- package/components/tryghost-mw-api-version-mismatch-5.77.0.tgz +0 -0
- package/components/tryghost-mw-cache-control-5.77.0.tgz +0 -0
- package/components/tryghost-mw-error-handler-5.77.0.tgz +0 -0
- package/components/tryghost-mw-session-from-token-5.77.0.tgz +0 -0
- package/components/tryghost-mw-update-user-last-seen-5.77.0.tgz +0 -0
- package/components/tryghost-mw-version-match-5.77.0.tgz +0 -0
- package/components/tryghost-mw-vhost-5.77.0.tgz +0 -0
- package/components/tryghost-nql-filter-expansions-5.77.0.tgz +0 -0
- package/components/tryghost-oembed-service-5.77.0.tgz +0 -0
- package/components/tryghost-package-json-5.77.0.tgz +0 -0
- package/components/tryghost-post-events-5.77.0.tgz +0 -0
- package/components/tryghost-post-revisions-5.77.0.tgz +0 -0
- package/components/tryghost-posts-service-5.77.0.tgz +0 -0
- package/components/tryghost-recommendations-5.77.0.tgz +0 -0
- package/components/tryghost-referrers-5.77.0.tgz +0 -0
- package/components/tryghost-security-5.77.0.tgz +0 -0
- package/components/tryghost-session-service-5.77.0.tgz +0 -0
- package/components/tryghost-settings-path-manager-5.77.0.tgz +0 -0
- package/components/tryghost-slack-notifications-5.77.0.tgz +0 -0
- package/components/tryghost-stats-service-5.77.0.tgz +0 -0
- package/components/tryghost-tiers-5.77.0.tgz +0 -0
- package/components/tryghost-update-check-service-5.77.0.tgz +0 -0
- package/components/tryghost-version-notifications-data-service-5.77.0.tgz +0 -0
- package/components/tryghost-webmentions-5.77.0.tgz +0 -0
- package/core/built/admin/assets/chunk.143.16228699a88898175515.js +0 -35
- package/core/server/services/segment/DomainEventsAnalytics.js +0 -109
- package/core/server/services/segment/index.js +0 -25
- /package/core/built/admin/assets/{chunk.664.99d0951b803d7ec00d8b.js.LICENSE.txt → chunk.160.f064da019dcb493ba212.js.LICENSE.txt} +0 -0
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<title>Ghost Admin</title>
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
<meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%22%2C%22cdnUrl%22%3A%22%22%2C%22editorUrl%22%3A%22%22%2C%22rootURL%22%3A%22%22%2C%22locationType%22%3A%22trailing-hash%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%2C%22Array%22%3Atrue%2C%22String%22%3Atrue%2C%22Function%22%3Afalse%7D%2C%22_APPLICATION_TEMPLATE_WRAPPER%22%3Afalse%2C%22_JQUERY_INTEGRATION%22%3Atrue%2C%22_TEMPLATE_ONLY_GLIMMER_COMPONENTS%22%3Atrue%7D%2C%22APP%22%3A%7B%22version%22%3A%225.
|
|
11
|
+
<meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%22%2C%22cdnUrl%22%3A%22%22%2C%22editorUrl%22%3A%22%22%2C%22rootURL%22%3A%22%22%2C%22locationType%22%3A%22trailing-hash%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%2C%22Array%22%3Atrue%2C%22String%22%3Atrue%2C%22Function%22%3Afalse%7D%2C%22_APPLICATION_TEMPLATE_WRAPPER%22%3Afalse%2C%22_JQUERY_INTEGRATION%22%3Atrue%2C%22_TEMPLATE_ONLY_GLIMMER_COMPONENTS%22%3Atrue%7D%2C%22APP%22%3A%7B%22version%22%3A%225.79%22%2C%22name%22%3A%22ghost-admin%22%7D%2C%22ember-simple-auth%22%3A%7B%7D%2C%22ember-websockets%22%3A%7B%22socketIO%22%3Atrue%7D%2C%22%40sentry%2Fember%22%3A%7B%22disablePerformance%22%3Atrue%2C%22sentry%22%3A%7B%7D%7D%2C%22ember-cli-mirage%22%3A%7B%22usingProxy%22%3Afalse%2C%22useDefaultPassthroughs%22%3Atrue%7D%2C%22exportApplicationGlobal%22%3Afalse%2C%22ember-load%22%3A%7B%22loadingIndicatorClass%22%3A%22ember-load-indicator%22%7D%2C%22editorFilename%22%3A%22koenig-lexical.umd.js%22%2C%22editorHash%22%3A%22f32944c498%22%2C%22adminXDemoFilename%22%3A%22admin-x-demo.js%22%2C%22adminXDemoHash%22%3A%22b6e4cf34df%22%2C%22adminXSettingsFilename%22%3A%22admin-x-settings.js%22%2C%22adminXSettingsHash%22%3A%22e10c30afc5%22%7D" />
|
|
12
12
|
|
|
13
13
|
<meta name="HandheldFriendly" content="True" />
|
|
14
14
|
<meta name="MobileOptimized" content="320" />
|
|
@@ -57,8 +57,8 @@
|
|
|
57
57
|
<div id="ember-basic-dropdown-wormhole"></div>
|
|
58
58
|
|
|
59
59
|
<script src="assets/vendor-6b83da0c6e6fede335947219c59e1543.js"></script>
|
|
60
|
-
<script src="assets/chunk.
|
|
61
|
-
<script src="assets/chunk.
|
|
62
|
-
<script src="assets/ghost-
|
|
60
|
+
<script src="assets/chunk.160.f064da019dcb493ba212.js"></script>
|
|
61
|
+
<script src="assets/chunk.524.fe4143d694c7ab008a78.js"></script>
|
|
62
|
+
<script src="assets/ghost-74787e16c2e5229de6164ddfe7426882.js"></script>
|
|
63
63
|
</body>
|
|
64
64
|
</html>
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
class ConnectionPoolInstrumentation {
|
|
2
|
+
constructor({knex, logging, metrics, config}) {
|
|
3
|
+
this.knex = knex;
|
|
4
|
+
this.pool = this.knex.client.pool;
|
|
5
|
+
this.logging = logging;
|
|
6
|
+
this.metrics = metrics;
|
|
7
|
+
this.enabled = config.get('telemetry:connectionPool');
|
|
8
|
+
this.requestStartTimes = {};
|
|
9
|
+
this.createStartTimes = {};
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Get the number of pending creates and acquires plus free and used connections
|
|
13
|
+
getPoolMetrics() {
|
|
14
|
+
return {
|
|
15
|
+
numPendingCreates: this.pool.numPendingCreates(),
|
|
16
|
+
numPendingAcquires: this.pool.numPendingAcquires(),
|
|
17
|
+
numFree: this.pool.numFree(),
|
|
18
|
+
numUsed: this.pool.numUsed()
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
handleCreateRequest(eventId) {
|
|
23
|
+
// Track when the request was submitted for calculating wait time
|
|
24
|
+
this.createStartTimes[eventId] = Date.now();
|
|
25
|
+
const poolMetrics = this.getPoolMetrics();
|
|
26
|
+
this.logging.debug(`[ConnectionPool] Creating a connection. EventID: ${eventId} Pending Creates: ${poolMetrics.numPendingCreates} Free: ${poolMetrics.numFree} Used: ${poolMetrics.numUsed}`);
|
|
27
|
+
this.metrics.metric('metrics-connection-pool', {
|
|
28
|
+
event: 'create-request',
|
|
29
|
+
eventId,
|
|
30
|
+
...poolMetrics
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
handleCreateSuccess(eventId, resource) {
|
|
35
|
+
// Calculate the time it took to create the connection
|
|
36
|
+
const timeToCreate = Date.now() - this.createStartTimes[eventId];
|
|
37
|
+
// Delete the start time so we don't leak memory
|
|
38
|
+
delete this.createStartTimes[eventId];
|
|
39
|
+
this.logging.debug(`[ConnectionPool] Created a connection. EventID: ${eventId} Connection ID: ${resource.connectionId} Knex ID: ${resource.__knexUid} Time to Create: ${timeToCreate}ms`);
|
|
40
|
+
this.metrics.metric('metrics-connection-pool', {
|
|
41
|
+
event: 'create-success',
|
|
42
|
+
eventId,
|
|
43
|
+
connectionId: resource.connectionId,
|
|
44
|
+
knexUid: resource.__knexUid,
|
|
45
|
+
timeToCreate
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
handleCreateFail(eventId, err) {
|
|
50
|
+
// Calculate the time it took to create the connection
|
|
51
|
+
const timeToFail = Date.now() - this.createStartTimes[eventId];
|
|
52
|
+
// Delete the start time so we don't leak memory
|
|
53
|
+
delete this.createStartTimes[eventId];
|
|
54
|
+
const poolMetrics = this.getPoolMetrics();
|
|
55
|
+
this.logging.error(`[ConnectionPool] Failed to create a connection. EventID: ${eventId} Time to Create: ${timeToFail}ms`, err);
|
|
56
|
+
this.metrics.metric('metrics-connection-pool', {
|
|
57
|
+
event: 'create-fail',
|
|
58
|
+
eventId,
|
|
59
|
+
timeToFail,
|
|
60
|
+
...poolMetrics
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
handleAcquireRequest(eventId) {
|
|
65
|
+
// Track when the request was submitted for calculating wait time
|
|
66
|
+
this.requestStartTimes[eventId] = Date.now();
|
|
67
|
+
const poolMetrics = this.getPoolMetrics();
|
|
68
|
+
this.logging.debug(`[ConnectionPool] Acquiring a connection. EventID: ${eventId} Pending Acquires: ${poolMetrics.numPendingAcquires} Free: ${poolMetrics.numFree} Used: ${poolMetrics.numUsed}`);
|
|
69
|
+
this.metrics.metric('metrics-connection-pool', {
|
|
70
|
+
event: 'acquire-request',
|
|
71
|
+
eventId,
|
|
72
|
+
...poolMetrics
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
handleAcquireSuccess(eventId, resource) {
|
|
77
|
+
// Calculate the time it took to acquire the connection
|
|
78
|
+
const timeToAcquire = Date.now() - this.requestStartTimes[eventId];
|
|
79
|
+
// Delete the start time so we don't leak memory
|
|
80
|
+
delete this.requestStartTimes[eventId];
|
|
81
|
+
// Track when the connection was acquired for calculating lifetime upon release
|
|
82
|
+
resource.connectionAcquired = Date.now();
|
|
83
|
+
this.logging.debug(`[ConnectionPool] Acquired a connection. EventID: ${eventId} Connection ID: ${resource.connectionId} Knex Id: ${resource.__knexUid} Time to Acquire: ${timeToAcquire}ms`);
|
|
84
|
+
this.metrics.metric('metrics-connection-pool', {
|
|
85
|
+
event: 'acquire-success',
|
|
86
|
+
eventId,
|
|
87
|
+
connectionId: resource.connectionId,
|
|
88
|
+
knexUid: resource.__knexUid,
|
|
89
|
+
timeToAcquire
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
handleAcquireFail(eventId, err) {
|
|
94
|
+
// Calculate the time it took to acquire the connection
|
|
95
|
+
const timeToFail = Date.now() - this.requestStartTimes[eventId];
|
|
96
|
+
// Delete the start time so we don't leak memory
|
|
97
|
+
delete this.requestStartTimes[eventId];
|
|
98
|
+
const poolMetrics = this.getPoolMetrics();
|
|
99
|
+
this.logging.error(`[ConnectionPool] Failed to acquire a connection. EventID: ${eventId} Time to Acquire: ${timeToFail}ms`, err);
|
|
100
|
+
this.metrics.metric('metrics-connection-pool', {
|
|
101
|
+
event: 'acquire-fail',
|
|
102
|
+
eventId,
|
|
103
|
+
timeToFail,
|
|
104
|
+
...poolMetrics
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
handleRelease(resource) {
|
|
109
|
+
const lifetime = Date.now() - resource.connectionAcquired;
|
|
110
|
+
this.logging.debug(`[ConnectionPool] Released a connection. Connection ID: ${resource.connectionId} Lifetime: ${lifetime}ms`);
|
|
111
|
+
this.metrics.metric('metrics-connection-pool', {
|
|
112
|
+
event: 'release',
|
|
113
|
+
connectionId: resource.connectionId,
|
|
114
|
+
knexUid: resource.__knexUid,
|
|
115
|
+
lifetime
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
instrument() {
|
|
120
|
+
if (this.enabled) {
|
|
121
|
+
// Check to make sure these event listeners haven't already been added
|
|
122
|
+
if (this.pool.emitter.eventNames().length === 0) {
|
|
123
|
+
// Fires when a connection is requested to be created
|
|
124
|
+
this.pool.on('createRequest', eventId => this.handleCreateRequest(eventId));
|
|
125
|
+
// Fires when a connection is successfully created
|
|
126
|
+
this.pool.on('createSuccess', (eventId, resource) => this.handleCreateSuccess(eventId, resource));
|
|
127
|
+
// Fires when a connection fails to be created
|
|
128
|
+
this.pool.on('createFail', (eventId, err) => this.handleCreateFail(eventId, err));
|
|
129
|
+
// Fires when a connection is requested from the pool
|
|
130
|
+
this.pool.on('acquireRequest', eventId => this.handleAcquireRequest(eventId));
|
|
131
|
+
// Fires when a connection is allocated from the pool
|
|
132
|
+
this.pool.on('acquireSuccess', (eventId, resource) => this.handleAcquireSuccess(eventId, resource));
|
|
133
|
+
// Fires when a connection fails to be allocated from the pool
|
|
134
|
+
this.pool.on('acquireFail', (eventId, err) => this.handleAcquireFail(eventId, err));
|
|
135
|
+
// Fires when a connection is released back into the pool
|
|
136
|
+
this.pool.on('release', resource => this.handleRelease(resource));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
module.exports = ConnectionPoolInstrumentation;
|
|
@@ -42,9 +42,15 @@ const readBackup = async (filename) => {
|
|
|
42
42
|
* Does an export, and stores this in a local file
|
|
43
43
|
*
|
|
44
44
|
* @param {Object} options
|
|
45
|
-
* @returns {Promise<String>}
|
|
45
|
+
* @returns {Promise<String> | null}
|
|
46
46
|
*/
|
|
47
47
|
const backup = async function backup(options = {}) {
|
|
48
|
+
// do not create backup if disabled in config (this is intended for large customers who will OOM node)
|
|
49
|
+
if (config.get('disableJSBackups')) {
|
|
50
|
+
logging.info('Database backup is disabled in Ghost config');
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
|
|
48
54
|
logging.info('Creating database backup');
|
|
49
55
|
|
|
50
56
|
const filename = await exporter.fileName(options);
|
|
@@ -4,8 +4,10 @@ const os = require('os');
|
|
|
4
4
|
const fs = require('fs');
|
|
5
5
|
|
|
6
6
|
const logging = require('@tryghost/logging');
|
|
7
|
+
const metrics = require('@tryghost/metrics');
|
|
7
8
|
const config = require('../../../shared/config');
|
|
8
9
|
const errors = require('@tryghost/errors');
|
|
10
|
+
const ConnectionPoolInstrumentation = require('./ConnectionPoolInstrumentation');
|
|
9
11
|
let knexInstance;
|
|
10
12
|
|
|
11
13
|
// @TODO:
|
|
@@ -62,6 +64,10 @@ function configure(dbConfig) {
|
|
|
62
64
|
|
|
63
65
|
if (!knexInstance && config.get('database') && config.get('database').client) {
|
|
64
66
|
knexInstance = knex(configure(config.get('database')));
|
|
67
|
+
if (config.get('telemetry:connectionPool')) {
|
|
68
|
+
const instrumentation = new ConnectionPoolInstrumentation({knex: knexInstance, logging, metrics, config});
|
|
69
|
+
instrumentation.instrument();
|
|
70
|
+
}
|
|
65
71
|
}
|
|
66
72
|
|
|
67
73
|
module.exports = knexInstance;
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
const logging = require('@tryghost/logging');
|
|
2
|
+
const metrics = require('@tryghost/metrics');
|
|
3
|
+
const config = require('../../../shared/config');
|
|
4
|
+
const ConnectionPoolInstrumentation = require('./ConnectionPoolInstrumentation');
|
|
5
|
+
|
|
1
6
|
let connection;
|
|
2
7
|
|
|
3
8
|
Object.defineProperty(exports, 'knex', {
|
|
@@ -5,6 +10,10 @@ Object.defineProperty(exports, 'knex', {
|
|
|
5
10
|
configurable: true,
|
|
6
11
|
get: function get() {
|
|
7
12
|
connection = connection || require('./connection');
|
|
13
|
+
if (config.get('telemetry:connectionPool')) {
|
|
14
|
+
const instrumentation = new ConnectionPoolInstrumentation({knex: connection, logging, metrics, config});
|
|
15
|
+
instrumentation.instrument();
|
|
16
|
+
}
|
|
8
17
|
return connection;
|
|
9
18
|
}
|
|
10
19
|
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
const {createTransactionalMigration} = require('../../utils');
|
|
2
|
+
const logging = require('@tryghost/logging');
|
|
3
|
+
|
|
4
|
+
module.exports = createTransactionalMigration(
|
|
5
|
+
async function up(knex) {
|
|
6
|
+
const portalPlansRaw = await knex('settings').select('value').where('key', 'portal_plans').first();
|
|
7
|
+
const freeTier = await knex('products').select('visibility').where('type', 'free').first();
|
|
8
|
+
|
|
9
|
+
if (!portalPlansRaw || !freeTier) {
|
|
10
|
+
logging.warn('Could not read `portal_plans` setting or `visibility` of the free tier - skipping migration');
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let portalPlans;
|
|
15
|
+
try {
|
|
16
|
+
portalPlans = JSON.parse(portalPlansRaw.value);
|
|
17
|
+
|
|
18
|
+
if (!portalPlans || !Array.isArray(portalPlans)) {
|
|
19
|
+
logging.warn('`portal_plans` setting is not valid - skipping migration');
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
} catch (err) {
|
|
23
|
+
logging.warn('Could not parse `portal_plans` setting - skipping migration');
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (portalPlans.includes('free') && freeTier.visibility === 'none') {
|
|
28
|
+
logging.info('`portal_plans` setting contains "free", but free tier is not visible - updating free tier visibility to public');
|
|
29
|
+
await knex('products').update('visibility', 'public').where('type', 'free');
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (!portalPlans.includes('free') && freeTier.visibility === 'public') {
|
|
34
|
+
logging.info('`portal_plans` setting does not contain "free", but free tier is visible - updating free tier visibility to none');
|
|
35
|
+
await knex('products').update('visibility', 'none').where('type', 'free');
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
async function down() {
|
|
41
|
+
// noop, as this is a data discrepancy fix
|
|
42
|
+
}
|
|
43
|
+
);
|
|
@@ -148,9 +148,13 @@ class Users {
|
|
|
148
148
|
* @returns
|
|
149
149
|
*/
|
|
150
150
|
async destroyUser(frameOptions) {
|
|
151
|
+
let filename = null;
|
|
151
152
|
const backupPath = await this.dbBackup.backup();
|
|
152
|
-
|
|
153
|
-
|
|
153
|
+
|
|
154
|
+
if (backupPath) {
|
|
155
|
+
const parsedFileName = path.parse(backupPath);
|
|
156
|
+
filename = `${parsedFileName.name}${parsedFileName.ext}`;
|
|
157
|
+
}
|
|
154
158
|
|
|
155
159
|
return this.models.Base.transaction(async (t) => {
|
|
156
160
|
frameOptions.transacting = t;
|
package/core/shared/labs.js
CHANGED
|
@@ -22,7 +22,8 @@ const GA_FEATURES = [
|
|
|
22
22
|
'signupForm',
|
|
23
23
|
'recommendations',
|
|
24
24
|
'listUnsubscribeHeader',
|
|
25
|
-
'filterEmailDisabled'
|
|
25
|
+
'filterEmailDisabled',
|
|
26
|
+
'newEmailAddresses'
|
|
26
27
|
];
|
|
27
28
|
|
|
28
29
|
// NOTE: this allowlist is meant to be used to filter out any unexpected
|
|
@@ -47,7 +48,6 @@ const ALPHA_FEATURES = [
|
|
|
47
48
|
// 'adminXOffers',
|
|
48
49
|
'filterEmailDisabled',
|
|
49
50
|
'adminXDemo',
|
|
50
|
-
'newEmailAddresses',
|
|
51
51
|
'portalImprovements'
|
|
52
52
|
];
|
|
53
53
|
|