Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow adjustable lockfile retry options via env #769

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion docs/modules/ROOT/pages/hardhat-upgrades.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -158,4 +158,25 @@ describe("Box", function() {
expect(value.toString()).to.equal('42');
});
});
----
----

[[troubleshooting]]
== Troubleshooting

[[error-elock]]
=== Error Code ELOCK
If used in an environment with lots of contracts being compiled, a timeout can occur related to lockfile usage for safe access to the validation file cache.

See https://github.com/OpenZeppelin/openzeppelin-upgrades/issues/537 for context.

If this occurs, you can tune the following parameters to increase leniency on lockfile acquisition.
The following env vars configure the retry options, see https://github.com/tim-kos/node-retry#retrytimeoutsoptions and https://github.com/tim-kos/node-retry#retryoperationoptions for option details.

[source, console]
----
OPENZEPPPELIN_HARDHAT_UPGRADES_LOCK_RETRY_OPTIONS_FACTOR
OPENZEPPPELIN_HARDHAT_UPGRADES_LOCK_RETRY_OPTIONS_MAXRETRYTIME
OPENZEPPPELIN_HARDHAT_UPGRADES_LOCK_RETRY_OPTIONS_MAXTIMEOUT
OPENZEPPPELIN_HARDHAT_UPGRADES_LOCK_RETRY_OPTIONS_MINTIMEOUT
OPENZEPPPELIN_HARDHAT_UPGRADES_LOCK_RETRY_OPTIONS_RETRIES
----
17 changes: 17 additions & 0 deletions packages/plugin-hardhat/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,23 @@ describe("Box", function() {
});
});
```
## Troubleshooting

### Error Code ELOCK
If used in an environment with lots of contracts being compiled, a timeout can occur related to lockfile usage for safe access to the validation file cache.

See https://github.com/OpenZeppelin/openzeppelin-upgrades/issues/537 for context.

If this occurs, you can tune the following parameters to increase leniency on lockfile acquisition.
The following env vars configure the retry options, see https://github.com/tim-kos/node-retry#retrytimeoutsoptions and https://github.com/tim-kos/node-retry#retryoperationoptions for option details.

```sh
OPENZEPPPELIN_HARDHAT_UPGRADES_LOCK_RETRY_OPTIONS_FACTOR
OPENZEPPPELIN_HARDHAT_UPGRADES_LOCK_RETRY_OPTIONS_MAXRETRYTIME
OPENZEPPPELIN_HARDHAT_UPGRADES_LOCK_RETRY_OPTIONS_MAXTIMEOUT
OPENZEPPPELIN_HARDHAT_UPGRADES_LOCK_RETRY_OPTIONS_MINTIMEOUT
OPENZEPPPELIN_HARDHAT_UPGRADES_LOCK_RETRY_OPTIONS_RETRIES
```

## Learn more
* Refer to the [API documentation](https://docs.openzeppelin.com/upgrades-plugins/api-hardhat-upgrades).
Expand Down
42 changes: 40 additions & 2 deletions packages/plugin-hardhat/src/utils/validations.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { promises as fs } from 'fs';
import path from 'path';
import lockfile from 'proper-lockfile';

import type { LockOptions } from 'proper-lockfile';
import type { HardhatRuntimeEnvironment } from 'hardhat/types';
import {
ValidationDataCurrent,
Expand All @@ -12,7 +12,17 @@ import {

async function lock(file: string) {
await fs.mkdir(path.dirname(file), { recursive: true });
return lockfile.lock(file, { retries: { minTimeout: 50, factor: 1.3 }, realpath: false });

const lockRetryOptions = getLockfileOptionsFromEnv();
const defaultLockRetryOptions = {
minTimeout: 50,
factor: 1.3,
};

return lockfile.lock(file, {
retries: lockRetryOptions ?? defaultLockRetryOptions,
realpath: false,
});
}

export async function writeValidations(hre: HardhatRuntimeEnvironment, newRunData: ValidationRunData): Promise<void> {
Expand All @@ -36,6 +46,34 @@ export async function writeValidations(hre: HardhatRuntimeEnvironment, newRunDat
}
}

/**
* Extracts lockfile options from environment variables.
* All env variables are prefixed with
* `OPENZEPPPELIN_HARDHAT_UPGRADES_LOCK_RETRY_OPTIONS_`
*
* @note We grab options from env rather than as optional subtask arguments because subtask argument overrides are supported only in hardhat 2.13.0 and above, breaking compatibility with our peer dependency of hardhat ^2.0.2
* @see https://github.com/NomicFoundation/hardhat/releases/tag/hardhat%402.13.0
*/
export function getLockfileOptionsFromEnv() {
const lockRetryOptions: LockOptions['retries'] = {};
const parentEnv = 'OPENZEPPPELIN_HARDHAT_UPGRADES_LOCK_RETRY_OPTIONS';
const childOptions = ['factor', 'maxRetryTime', 'maxTimeout', 'minTimeout', 'retries'] as const;

childOptions.forEach(option => {
const optionEnv = process.env[`${parentEnv}_${option.toUpperCase()}`];

if (optionEnv) {
lockRetryOptions[option] = Number(optionEnv);
}
});

if (Object.keys(lockRetryOptions).length === 0) {
return null;
}

return lockRetryOptions;
}

export async function readValidations(
hre: HardhatRuntimeEnvironment,
acquireLock = true,
Expand Down