-
Notifications
You must be signed in to change notification settings - Fork 210
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
[bug] Kiota generate is not idempotent #2442
Comments
can you provide more specific details about what's changing from run to run? |
Sure use this OpenAPI document spec.zip, with the latest
I can observe various spurious class declarations such as: public class ConnectorNamespace extends VersionMetadata_collections implements Parsable { where, sometimes, the expected output is generated instead: public class ConnectorNamespace extends ObjectReference implements Parsable { or again: public class ConnectorType extends VersionMetadata_collections implements Parsable { instead of (but sometimes it works ...): public class ConnectorType extends ObjectReference implements Parsable { all in all the major issue seems to be related to an incorrectly computed hierarchy, but I haven't narrowed down the issue any further. |
@baywet I started anyhow looking into this issue, but I'm afraid I would need your assistance, sorry for bothering you. I'm starting to be convinced that the issue is caused by a colliding Key in the InheritanceIndex/DiscriminatorMappings:
changing this part of the code:
to take into account only primitive types or by adding the type to the Key I can see progress (at least the build is reproducible and compiles in Java). |
No worries, hopefully we get to the bottom of this together and unblock you. A few remarks on the version metadata aspect: components:
schemas:
VersionMetadata:
allOf: #this is a canonical inheritance pattern and should be fine
- $ref: "#/components/schemas/ObjectReference"
- type: object
example:
kind: "APIVersion"
id: "v1"
href: "/api/connector_mgmt/v1"
collections:
- id: "kafkas"
href: "/api/connector_mgmt/v1/kafka_connectors"
kind: "ConnectorList"
properties:
collections:
type: array
items:
allOf: #this is a bit weird but we have strategies in place to flatten empty all/any/one ofs you might want to try to flatten it in the document
- $ref: "#/components/schemas/ObjectReference" I hope all of this helps, sorry I can't spend more time on this at the moment. |
Thanks a lot for getting back @baywet !
Yes, I noticed and tested this change this morning and sadly it doesn't fix this issue.
Right, let me do it first 👍
You are right, possibly the peculiarity of the document we are looking at is that it contains mutually recursive models, depending on the pattern used to visit the tree this can have consequences. |
Ok, I spent the time to bisect this issue, this is the minimal reproducer that can be used: openapi: 3.0.0
info:
title: Connector Management API
version: 0.1.0
paths:
"/api/connector_mgmt/v1":
get:
operationId: getVersionMetadata
summary: Returns the version metadata
description: Returns the version metadata
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/VersionMetadata'
description: Version metadata
"/api/connector_mgmt/v1/kafka_connector_types":
get:
operationId: getConnectorTypes
summary: Returns a list of connector types
description: Returns a list of connector types
responses:
"200":
content:
application/json:
schema:
$ref: "#/components/schemas/ConnectorType"
description: A list of connector types
components:
schemas:
ObjectReference:
type: object
properties:
id:
type: string
VersionMetadata:
allOf:
- $ref: "#/components/schemas/ObjectReference"
- type: object
properties:
collections:
type: array
items:
allOf:
- $ref: "#/components/schemas/ObjectReference"
ConnectorType:
description: Represents a connector type supported by the API
required:
- name
allOf:
- $ref: "#/components/schemas/ObjectReference"
- type: object
properties:
name:
description: Name of the connector type.
type: string This spec is going to proce about half of the times: public class ConnectorType extends VersionMetadata_collections implements Parsable { and: public class ConnectorType extends ObjectReference implements Parsable { |
The problem seems to be caused by: items:
allOf:
- $ref: "#/components/schemas/ObjectReference" in (sorry for being chatty on this Issue, I'm trying to dump the updates as I get them) |
No, this is great, we can follow the progress this way. |
yes, it solves it! Tentatively opened #2452 , |
I think the following method is getting derailed again by the allOf node. kiota/src/Kiota.Builder/KiotaBuilder.cs Line 1324 in a9a0dd1
Because it relies on that method, which doesn't tolerate "empty nodes".
Fixing that aspect will probably have a better result than trying to order things. |
Thanks for the hint @baywet , yes, you are probably right, I have attempted various things with not much result. i.e.: I can prove that the value extracted by
do you have any references I can lookup to follow the history? |
unfortunately there's not much documentation on that aspect, it's mostly trial and error based on a corpus of API descriptions. And that specific edge case didn't come across during our testing. You might be able to find helpful information by digging through the issues on the repo, but that's about it.
|
Thanks a lot for the quick turn around. Your proposal of fixing/verifying #2438 first sounds good to me. I'll try to find time or someone else to look into, but I cannot guarantee much at this point. |
This causes quite severe corruption of the CodeModel. Many threads concurrently start creating the same models and start adding properties. The result is undefined for larger models and will be different on every run. This probably fixes (or at least improves the situation for) microsoft#2442.
This causes quite severe corruption of the CodeModel. Many threads concurrently start creating the same models and start adding properties. The result is undefined for larger models and will be different on every run. This probably fixes (or at least improves the situation for) microsoft#2442.
This causes quite severe corruption of the CodeModel. Many threads concurrently start creating the same models and start adding properties. The result is undefined for larger models and will be different on every run. This probably fixes (or at least improves the situation for) microsoft#2442.
While working on #2676 I found out something: renaming code elements has a high potential of introducing fork trees is not done right. Those fork trees mean that sometimes multiple writers fire for the same file. And they don't necessarily always fire in the same order since the code dom is built in a parallels way (no order guaranteed). Additionally @papegaaij comment about locking and duplication of work in the builder made me realize two things:
|
This causes quite severe corruption of the CodeModel. Many threads concurrently start creating the same models and start adding properties. The result is undefined for larger models and will be different on every run. This probably fixes (or at least improves the situation for) microsoft#2442.
There seem to be 2 major contributors to inconsistencies between runs:
The first category can be suppressed by now by setting the The second category results from the fact that Kiota can end up generating the same type via different routes. This is expected and fine, but the outcome should always be identical. #2861 and #2863 already address some of the issues mentioned in this ticket, but there could be more. With these changes (and parallelism switched off), I was able to consistently generate the same code over many runs for the Graph API with the Go target. Parallelism does increase the impact of these issues by making the path that generates a type first less predictable. You can get a quick overview of files that have changed between runs by calculating sha1sums:
|
@andreaTP recent changes probably have fixed this issue. Can you re-validate idempotency is still an issue on generation? Thanks! |
Sure, I'm on holiday those days, when I'm back I'll give it a shot! |
The tests I've ran all produce stable output now, but it could be there are still some issues remaining. I think it would be best if @andreaTP tests this with his cases. |
Sorry for the delay, I'm now working on verifying this, and I'll get back soon with the results. |
Sorry again for the delay in giving feedback on this one, I'm afraid the issues are not completely solved just yet. From the branch is pretty easy to reproduce by using, for example: ./it/compare-generation.ps1 -descriptionUrl apisguru::stripe.com -language java -preserveOutput consistently fails on my machine and in CI. |
Issue discovered in #2438 .
The generator is currently emitting different results in different runs.
We expect the generator to be fully idempotent so that given the same input the same output is produced even in the case of edge cases.
More specifically, even applying all the requested workarounds the output of the generator vary for different runs and is reproducible by running this script:
https://gist.github.com/andreaTP/08180453508dc80dc1ae7953efe0dc20
The text was updated successfully, but these errors were encountered: