Skip to content

Commit b8f92a9

Browse files
committed
Merge branch 'main' into cmartins-bumpNode
2 parents 45631ef + ef24250 commit b8f92a9

21 files changed

Lines changed: 27530 additions & 621 deletions

File tree

.github/actions/javascript/reassureStabilityCheck/index.js

Lines changed: 26891 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* NOTE: After changes to the file it needs to be compiled using [`ncc`](https://github.com/vercel/ncc)
3+
* Example: ncc build -t reassureStabilityCheck.ts -o index.js
4+
*/
5+
6+
import * as core from '@actions/core';
7+
import {execSync} from 'child_process';
8+
9+
async function run() {
10+
try {
11+
console.log('Running Reassure stability check...');
12+
execSync('npx reassure check-stability --verbose', {stdio: 'inherit'});
13+
14+
console.log('Validating Reassure stability results...');
15+
execSync('node .github/actions/javascript/validateReassureOutput', {stdio: 'inherit'});
16+
17+
return true;
18+
} catch (error) {
19+
console.log('error: ', error);
20+
core.setFailed(error.message);
21+
process.exit(1);
22+
}
23+
}
24+
25+
run();
26+
27+
export default run;

.github/actions/javascript/validateReassureOutput/action.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ inputs:
77
ALLOWED_RELATIVE_DURATION_DEVIATION:
88
description: Allowable percentage deviation for the mean duration in regression test results.
99
required: true
10+
IS_VALIDATING_STABILITY:
11+
description: Whether the workflow is validating a Reassure stability check or not.
12+
required: true
1013
runs:
1114
using: 'node20'
1215
main: './index.js'

.github/actions/javascript/validateReassureOutput/index.js

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24966,12 +24966,25 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
2496624966
Object.defineProperty(exports, "__esModule", ({ value: true }));
2496724967
const core = __importStar(__nccwpck_require__(2186));
2496824968
const fs_1 = __importDefault(__nccwpck_require__(7147));
24969+
function getInputOrEnv(name) {
24970+
try {
24971+
return core.getInput(name, { required: true });
24972+
}
24973+
catch (_a) {
24974+
const envProperty = process.env[name];
24975+
if (!envProperty) {
24976+
throw new Error(`'${name}' env property not defined.`);
24977+
}
24978+
return envProperty;
24979+
}
24980+
}
2496924981
function run() {
2497024982
return __awaiter(this, void 0, void 0, function* () {
2497124983
try {
2497224984
const regressionOutput = JSON.parse(fs_1.default.readFileSync('.reassure/output.json', 'utf8'));
24973-
const allowedDurationDeviation = Number(core.getInput('ALLOWED_DURATION_DEVIATION', { required: true }));
24974-
const durationDeviationPercentage = Number(core.getInput('ALLOWED_RELATIVE_DURATION_DEVIATION', { required: true }));
24985+
const allowedDurationDeviation = Number(getInputOrEnv('ALLOWED_DURATION_DEVIATION'));
24986+
const durationDeviationPercentage = Number(getInputOrEnv('ALLOWED_RELATIVE_DURATION_DEVIATION'));
24987+
const isValidatingStability = Boolean(getInputOrEnv('IS_VALIDATING_STABILITY'));
2497524988
if (regressionOutput.significant === undefined || regressionOutput.significant.length === 0) {
2497624989
console.log('No significant data available. Exiting...');
2497724990
return true;
@@ -25018,7 +25031,12 @@ function run() {
2501825031
});
2501925032
const shouldFailWorkflow = outputs.some((output) => output.isDeviationExceeded);
2502025033
if (shouldFailWorkflow) {
25021-
core.setFailed(`🔴 Duration deviation exceeded the allowed ranges in one or more measurements.`);
25034+
if (isValidatingStability) {
25035+
core.setFailed(`🔴 Duration deviation exceeded the allowed ranges in one or more measurements during the stability checks.`);
25036+
}
25037+
else {
25038+
core.setFailed(`🔴 Duration deviation exceeded the allowed ranges in one or more measurements.`);
25039+
}
2502225040
}
2502325041
return true;
2502425042
}

.github/actions/javascript/validateReassureOutput/validateReassureOutput.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,25 @@ type MeasurementOutput = {
1414
isDeviationExceeded: boolean;
1515
};
1616

17+
function getInputOrEnv(name: string): string {
18+
try {
19+
return core.getInput(name, {required: true});
20+
} catch {
21+
const envProperty = process.env[name];
22+
if (!envProperty) {
23+
throw new Error(`'${name}' env property not defined.`);
24+
}
25+
26+
return envProperty;
27+
}
28+
}
29+
1730
async function run() {
1831
try {
1932
const regressionOutput: CompareResult = JSON.parse(fs.readFileSync('.reassure/output.json', 'utf8'));
20-
const allowedDurationDeviation = Number(core.getInput('ALLOWED_DURATION_DEVIATION', {required: true}));
21-
const durationDeviationPercentage = Number(core.getInput('ALLOWED_RELATIVE_DURATION_DEVIATION', {required: true}));
33+
const allowedDurationDeviation = Number(getInputOrEnv('ALLOWED_DURATION_DEVIATION'));
34+
const durationDeviationPercentage = Number(getInputOrEnv('ALLOWED_RELATIVE_DURATION_DEVIATION'));
35+
const isValidatingStability = Boolean(getInputOrEnv('IS_VALIDATING_STABILITY'));
2236

2337
if (regressionOutput.significant === undefined || regressionOutput.significant.length === 0) {
2438
console.log('No significant data available. Exiting...');
@@ -77,7 +91,11 @@ async function run() {
7791

7892
const shouldFailWorkflow = outputs.some((output) => output.isDeviationExceeded);
7993
if (shouldFailWorkflow) {
80-
core.setFailed(`🔴 Duration deviation exceeded the allowed ranges in one or more measurements.`);
94+
if (isValidatingStability) {
95+
core.setFailed(`🔴 Duration deviation exceeded the allowed ranges in one or more measurements during the stability checks.`);
96+
} else {
97+
core.setFailed(`🔴 Duration deviation exceeded the allowed ranges in one or more measurements.`);
98+
}
8199
}
82100

83101
return true;

.github/workflows/reassurePerfTests.yml

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,27 @@ jobs:
2525
node-version-file: '.nvmrc'
2626

2727
- name: Install dependencies
28-
run: npm install
28+
run: npm ci
2929

30-
- name: Run Reassure baseline tests
31-
run: npx reassure --baseline --verbose
30+
- name: Reassure stability check
31+
uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08
32+
with:
33+
timeout_minutes: 30
34+
max_attempts: 3
35+
retry_on: error
36+
command: node .github/actions/javascript/reassureStabilityCheck
37+
env:
38+
ALLOWED_DURATION_DEVIATION: 10
39+
ALLOWED_RELATIVE_DURATION_DEVIATION: 20
40+
IS_VALIDATING_STABILITY: true
3241

3342
- name: Checkout PR head SHA
3443
run: |
3544
git fetch origin ${{ github.event.pull_request.head.sha }} --no-tags --depth=1
3645
git switch --force --detach ${{ github.event.pull_request.head.sha }}
3746
3847
- name: Reinstall dependencies
39-
run: npm install --force
48+
run: npm ci
4049

4150
- name: Run Reassure delta tests
4251
run: npx reassure --branch --verbose
@@ -49,9 +58,10 @@ jobs:
4958
if-no-files-found: ignore
5059
include-hidden-files: true
5160

52-
- name: Validate output.json
53-
id: validateReassureOutput
61+
- name: Validate Reassure results
62+
id: validateReassureResults
5463
uses: ./.github/actions/javascript/validateReassureOutput
5564
with:
5665
ALLOWED_DURATION_DEVIATION: 10
5766
ALLOWED_RELATIVE_DURATION_DEVIATION: 20
67+
IS_VALIDATING_STABILITY: false

API.md

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,16 @@
99
<dd><p>Initialize the store with actions and listening for storage events</p>
1010
</dd>
1111
<dt><a href="#connect">connect(connectOptions)</a> ⇒</dt>
12+
<dd><p>Connects to an Onyx key given the options passed and listens to its changes.
13+
This method will be deprecated soon. Please use <code>Onyx.connectWithoutView()</code> instead.</p>
14+
</dd>
15+
<dt><a href="#connectWithoutView">connectWithoutView(connectOptions)</a> ⇒</dt>
1216
<dd><p>Connects to an Onyx key given the options passed and listens to its changes.</p>
1317
</dd>
1418
<dt><a href="#disconnect">disconnect(connection)</a></dt>
1519
<dd><p>Disconnects and removes the listener from the Onyx key.</p>
1620
</dd>
17-
<dt><a href="#set">set(key, value)</a></dt>
21+
<dt><a href="#set">set(key, value, options)</a></dt>
1822
<dd><p>Write a value to our store with the given key</p>
1923
</dd>
2024
<dt><a href="#multiSet">multiSet(data)</a></dt>
@@ -66,6 +70,33 @@ Initialize the store with actions and listening for storage events
6670

6771
## connect(connectOptions) ⇒
6872
Connects to an Onyx key given the options passed and listens to its changes.
73+
This method will be deprecated soon. Please use `Onyx.connectWithoutView()` instead.
74+
75+
**Kind**: global function
76+
**Returns**: The connection object to use when calling `Onyx.disconnect()`.
77+
78+
| Param | Description |
79+
| --- | --- |
80+
| connectOptions | The options object that will define the behavior of the connection. |
81+
| connectOptions.key | The Onyx key to subscribe to. |
82+
| connectOptions.callback | A function that will be called when the Onyx data we are subscribed changes. |
83+
| connectOptions.waitForCollectionCallback | If set to `true`, it will return the entire collection to the callback as a single object. |
84+
| connectOptions.withOnyxInstance | The `withOnyx` class instance to be internally passed. **Only used inside `withOnyx()` HOC.** |
85+
| connectOptions.statePropertyName | The name of the component's prop that is connected to the Onyx key. **Only used inside `withOnyx()` HOC.** |
86+
| connectOptions.displayName | The component's display name. **Only used inside `withOnyx()` HOC.** |
87+
| connectOptions.selector | This will be used to subscribe to a subset of an Onyx key's data. **Only used inside `useOnyx()` hook or `withOnyx()` HOC.** Using this setting on `useOnyx()` or `withOnyx()` can have very positive performance benefits because the component will only re-render when the subset of data changes. Otherwise, any change of data on any property would normally cause the component to re-render (and that can be expensive from a performance standpoint). |
88+
89+
**Example**
90+
```ts
91+
const connection = Onyx.connectWithoutView({
92+
key: ONYXKEYS.SESSION,
93+
callback: onSessionChange,
94+
});
95+
```
96+
<a name="connectWithoutView"></a>
97+
98+
## connectWithoutView(connectOptions) ⇒
99+
Connects to an Onyx key given the options passed and listens to its changes.
69100

70101
**Kind**: global function
71102
**Returns**: The connection object to use when calling `Onyx.disconnect()`.
@@ -83,7 +114,7 @@ Connects to an Onyx key given the options passed and listens to its changes.
83114

84115
**Example**
85116
```ts
86-
const connection = Onyx.connect({
117+
const connection = Onyx.connectWithoutView({
87118
key: ONYXKEYS.SESSION,
88119
callback: onSessionChange,
89120
});
@@ -97,11 +128,11 @@ Disconnects and removes the listener from the Onyx key.
97128

98129
| Param | Description |
99130
| --- | --- |
100-
| connection | Connection object returned by calling `Onyx.connect()`. |
131+
| connection | Connection object returned by calling `Onyx.connect()` or `Onyx.connectWithoutView()`. |
101132

102133
**Example**
103134
```ts
104-
const connection = Onyx.connect({
135+
const connection = Onyx.connectWithoutView({
105136
key: ONYXKEYS.SESSION,
106137
callback: onSessionChange,
107138
});
@@ -110,7 +141,7 @@ Onyx.disconnect(connection);
110141
```
111142
<a name="set"></a>
112143

113-
## set(key, value)
144+
## set(key, value, options)
114145
Write a value to our store with the given key
115146

116147
**Kind**: global function
@@ -119,6 +150,7 @@ Write a value to our store with the given key
119150
| --- | --- |
120151
| key | ONYXKEY to set |
121152
| value | value to store |
153+
| options | optional configuration object |
122154

123155
<a name="multiSet"></a>
124156

README.md

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,26 @@ API.Authenticate(params)
5959

6060
The data will then be cached and stored via [`AsyncStorage`](https://github.com/react-native-async-storage/async-storage).
6161

62+
### Performance Options for Large Objects
63+
64+
For performance-critical scenarios with large objects, `Onyx.set()` accepts optional flag to skip expensive operations:
65+
66+
```javascript
67+
Onyx.set(ONYXKEYS.LARGE_DATA, computedValue, {
68+
skipCacheCheck: true, // Skip deep equality check
69+
});
70+
```
71+
72+
**Options:**
73+
- `skipCacheCheck`: Skips the deep equality comparison with the cached value. By default, Onyx compares new values against cached ones to avoid unnecessary updates. For large objects, this comparison can be expensive.
74+
75+
#### When to Use SetOptions
76+
- **Use `skipCacheCheck: true`** for:
77+
- Large objects where deep equality checking is expensive
78+
- Values that you know have changed
79+
80+
**Note**: These option is recommended only for large objects where performance is critical. Most use cases should use the standard `Onyx.set(key, value)` syntax.
81+
6282
## Merging data
6383

6484
We can also use `Onyx.merge()` to merge new `Object` or `Array` data in with existing data.
@@ -169,16 +189,7 @@ export default withOnyx({
169189
})(App);
170190
```
171191

172-
Differently from `useOnyx()`, `withOnyx()` will delay the rendering of the wrapped component until all keys/entities have been fetched and passed to the component, this can be convenient for simple cases. This however, can really delay your application if many entities are connected to the same component, you can pass an `initialValue` to each key to allow Onyx to eagerly render your component with this value.
173-
174-
```javascript
175-
export default withOnyx({
176-
session: {
177-
key: ONYXKEYS.SESSION,
178-
initialValue: {}
179-
},
180-
})(App);
181-
```
192+
Differently from `useOnyx()`, `withOnyx()` will delay the rendering of the wrapped component until all keys/entities have been fetched and passed to the component, this can be convenient for simple cases. This however, can really delay your application if many entities are connected to the same component.
182193

183194
Additionally, if your component has many keys/entities when your component will mount but will receive many updates as data is fetched from DB and passed down to it, as every key that gets fetched will trigger a `setState` on the `withOnyx` HOC. This might cause re-renders on the initial mounting, preventing the component from mounting/rendering in reasonable time, making your app feel slow and even delaying animations.
184195

@@ -194,8 +205,7 @@ const App = ({session, markReadyForHydration}) => (
194205
// Second argument to funciton is `shouldDelayUpdates`
195206
export default withOnyx({
196207
session: {
197-
key: ONYXKEYS.SESSION,
198-
initialValue: {}
208+
key: ONYXKEYS.SESSION
199209
},
200210
}, true)(App);
201211
```
@@ -379,7 +389,7 @@ If a platform needs to use a separate library (like using MMVK for react-native)
379389

380390
[Docs](./API.md)
381391

382-
# Storage Eviction
392+
# Cache Eviction
383393

384394
Different platforms come with varying storage capacities and Onyx has a way to gracefully fail when those storage limits are encountered. When Onyx fails to set or modify a key the following steps are taken:
385395
1. Onyx looks at a list of recently accessed keys (access is defined as subscribed to or modified) and locates the key that was least recently accessed

0 commit comments

Comments
 (0)