@malloy-publisher/server 0.0.83 → 0.0.85

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.
@@ -1,4 +1,5 @@
1
1
  import { BaseConnection } from "@malloydata/malloy/connection";
2
+ import { Mutex } from "async-mutex";
2
3
  import * as fs from "fs/promises";
3
4
  import * as path from "path";
4
5
  import { components } from "../api";
@@ -12,6 +13,7 @@ type ApiProject = components["schemas"]["Project"];
12
13
 
13
14
  export class Project {
14
15
  private packages: Map<string, Package> = new Map();
16
+ private packageMutexes = new Map<string, Mutex>();
15
17
  private malloyConnections: Map<string, BaseConnection>;
16
18
  private apiConnections: ApiConnection[];
17
19
  private internalConnections: InternalConnection[];
@@ -129,14 +131,15 @@ export class Project {
129
131
  .filter((file) => file.isDirectory())
130
132
  .map(async (directory) => {
131
133
  try {
132
- const _package = await this.getPackage(
133
- directory.name,
134
- false,
134
+ return (
135
+ await this.getPackage(directory.name, false)
136
+ ).getPackageMetadata();
137
+ } catch (error) {
138
+ console.log(
139
+ `Failed to load package: ${directory.name} due to : ${error}`,
135
140
  );
136
- const metadata = _package.getPackageMetadata();
137
- return metadata;
138
- } catch {
139
141
  // Directory did not contain a valid package.json file -- therefore, it's not a package.
142
+ // Or it timed out
140
143
  return undefined;
141
144
  }
142
145
  }),
@@ -155,21 +158,33 @@ export class Project {
155
158
  packageName: string,
156
159
  reload: boolean,
157
160
  ): Promise<Package> {
158
- let _package = this.packages.get(packageName);
159
- if (_package === undefined || reload) {
161
+ // We need to acquire the mutex to prevent a thundering herd of requests from creating the
162
+ // package multiple times.
163
+ let packageMutex = this.packageMutexes.get(packageName);
164
+ if (!packageMutex) {
165
+ packageMutex = new Mutex();
166
+ this.packageMutexes.set(packageName, packageMutex);
167
+ }
168
+
169
+ return await packageMutex.runExclusive(async () => {
170
+ const _package = this.packages.get(packageName);
171
+ if (_package !== undefined && !reload) {
172
+ return _package;
173
+ }
174
+
160
175
  try {
161
- _package = await Package.create(
176
+ const _package = await Package.create(
162
177
  this.projectName,
163
178
  packageName,
164
179
  path.join(this.projectPath, packageName),
165
180
  this.malloyConnections,
166
181
  );
167
182
  this.packages.set(packageName, _package);
183
+ return _package;
168
184
  } catch (error) {
169
185
  this.packages.delete(packageName);
170
186
  throw error;
171
187
  }
172
- }
173
- return _package;
188
+ });
174
189
  }
175
190
  }