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

Closed
grigasp opened this issue Jan 24, 2025 · 1 comment · Fixed by #7623
Closed

ecschema-metadata: Race condition when creating FormatterSpec #7603

grigasp opened this issue Jan 24, 2025 · 1 comment · 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

@grigasp
Copy link
Member Author

grigasp commented Feb 13, 2025

@StefanApfel-Bentley, did this get backported to 4.11? I believe @karolis-zukauskas was asking for that.

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