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

ecschema-metadata: Race condition when creating FormatterSpec #7603

Open
grigasp opened this issue Jan 24, 2025 · 0 comments · Fixed by #7623
Open

ecschema-metadata: Race condition when creating FormatterSpec #7603

grigasp opened this issue Jan 24, 2025 · 0 comments · Fixed by #7623
Assignees
Labels
bug Something isn't working ecschema Issues related to the various ecschema packages

Comments

@grigasp
Copy link
Member

grigasp commented Jan 24, 2025

Describe the bug

Calling FormatterSpec.create several times in parallel on same units causes the following error:

UnitConverter.ts:87 Uncaught (in promise) _BentleyError: Source and target units do not have matching base units
    at UnitConverter.processUnits (UnitConverter.ts:87:13)
    at async SchemaUnitProvider.getConversion (SchemaUnitProvider.ts:180:24)
    at async _FormatterSpec.getUnitConversions (FormatterSpec.ts:81:28)
    at async _FormatterSpec.create (FormatterSpec.ts:110:47)

To Reproduce

Calling this function should reproduce the error on await Promise.all line:

async function createFormatterSpecMetersToMillimeters(imodel: IModelConnection) {
  const schemaContext = new SchemaContext();
  schemaContext.addLocater(new ECSchemaRpcLocater(imodel.getRpcProps()));
  const unitsProvider = new SchemaUnitProvider(schemaContext);

  const persistenceUnit = await unitsProvider.findUnitByName("Units.M");

  // matches AecUnits:LENGTH_SHORT
  const formatProps = {
    schemaItemType: "Format",
    label: "realu",
    type: "Decimal",
    precision: 2,
    formatTraits: ["KeepSingleZero", "KeepDecimalPoint", "ShowUnitLabel"],
    name: "Formats.DefaultRealU(2)[Units.MM]",
    parent: "Formats.DefaultRealU",
    composite: { units: [{ name: "Units.MM" }] },
  };
  const format = await Format.createFromJSON("", unitsProvider, formatProps);

  const [formatterSpec1, formatterSpec2] = await Promise.all([
    FormatterSpec.create("", format, unitsProvider, persistenceUnit),
    FormatterSpec.create("", format, unitsProvider, persistenceUnit),
  ]);

  // eslint-disable-next-line no-console
  console.log(`5 meters = ${formatterSpec1.applyFormatting(5)} = ${formatterSpec2.applyFormatting(5)}`);
}

Expected behavior

Both FormatterSpec objects are created successfully and can be used to format values.

Desktop (please complete the applicable information):

  • OS: Windows 11
  • Browser: Chrome, Firefox
  • iTwin.js Version: 4.10.1

Additional context

Originally reported in iTwin/presentation#848

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working ecschema Issues related to the various ecschema packages
Projects
None yet
3 participants