Example: Dealing with partial failures

Frequency of useCommon
Actors
  • The UCloud/Core service user (ucloud)
  • The provider (provider)
Communication Flow: Kotlin
/* In this example, we will discover how a provider should deal with a partial failure. */

ResourceProvider.create.call(
    bulkRequestOf(ExampleResource(
        createdAt = 1635170395571, 
        id = "1234", 
        owner = ResourceOwner(
            createdBy = "user", 
            project = null, 
        ), 
        permissions = ResourcePermissions(
            myself = listOf(Permission.ADMIN), 
            others = emptyList(), 
        ), 
        specification = ExampleResource.Spec(
            product = ProductReference(
                category = "example-compute", 
                id = "example-compute", 
                provider = "example", 
            ), 
            start = 0, 
            target = 100, 
        ), 
        status = ExampleResource.Status(
            resolvedProduct = null, 
            resolvedSupport = null, 
            state = State.RUNNING, 
            value = 10, 
        ), 
        updates = listOf(ExampleResource.Update(
            currentValue = null, 
            newState = State.PENDING, 
            status = "We are about to start counting!", 
            timestamp = 1635170395571, 
        ), ExampleResource.Update(
            currentValue = 10, 
            newState = State.RUNNING, 
            status = "We are now counting!", 
            timestamp = 1635170395571, 
        )), 
        providerGeneratedId = "1234", 
    ), ExampleResource(
        createdAt = 1635170395571, 
        id = "51214", 
        owner = ResourceOwner(
            createdBy = "user", 
            project = null, 
        ), 
        permissions = ResourcePermissions(
            myself = listOf(Permission.ADMIN), 
            others = emptyList(), 
        ), 
        specification = ExampleResource.Spec(
            product = ProductReference(
                category = "example-compute", 
                id = "example-compute", 
                provider = "example", 
            ), 
            start = 0, 
            target = 100, 
        ), 
        status = ExampleResource.Status(
            resolvedProduct = null, 
            resolvedSupport = null, 
            state = State.RUNNING, 
            value = 10, 
        ), 
        updates = listOf(ExampleResource.Update(
            currentValue = null, 
            newState = State.PENDING, 
            status = "We are about to start counting!", 
            timestamp = 1635170395571, 
        ), ExampleResource.Update(
            currentValue = 10, 
            newState = State.RUNNING, 
            status = "We are now counting!", 
            timestamp = 1635170395571, 
        )), 
        providerGeneratedId = "51214", 
    )),
    ucloud
).orThrow()

/*
HttpStatusCode(value=500, description=Internal Server Error)
*/

/* In this case, imagine that the provider failed to create the second resource. This should
immediately trigger cleanup on the provider, if the first resource was already created. The provider
should then respond with an appropriate error message. Providers should not attempt to only
partially create the resources. */
Communication Flow: TypeScript
/* In this example, we will discover how a provider should deal with a partial failure. */

// Authenticated as ucloud
await callAPI(ExampleProviderPROVIDERIDApi.create(
    {
        "items": [
            {
                "id": "1234",
                "specification": {
                    "start": 0,
                    "target": 100,
                    "product": {
                        "id": "example-compute",
                        "category": "example-compute",
                        "provider": "example"
                    }
                },
                "createdAt": 1635170395571,
                "status": {
                    "state": "RUNNING",
                    "value": 10,
                    "resolvedSupport": null,
                    "resolvedProduct": null
                },
                "updates": [
                    {
                        "timestamp": 1635170395571,
                        "status": "We are about to start counting!",
                        "newState": "PENDING",
                        "currentValue": null
                    },
                    {
                        "timestamp": 1635170395571,
                        "status": "We are now counting!",
                        "newState": "RUNNING",
                        "currentValue": 10
                    }
                ],
                "owner": {
                    "createdBy": "user",
                    "project": null
                },
                "permissions": {
                    "myself": [
                        "ADMIN"
                    ],
                    "others": [
                    ]
                }
            },
            {
                "id": "51214",
                "specification": {
                    "start": 0,
                    "target": 100,
                    "product": {
                        "id": "example-compute",
                        "category": "example-compute",
                        "provider": "example"
                    }
                },
                "createdAt": 1635170395571,
                "status": {
                    "state": "RUNNING",
                    "value": 10,
                    "resolvedSupport": null,
                    "resolvedProduct": null
                },
                "updates": [
                    {
                        "timestamp": 1635170395571,
                        "status": "We are about to start counting!",
                        "newState": "PENDING",
                        "currentValue": null
                    },
                    {
                        "timestamp": 1635170395571,
                        "status": "We are now counting!",
                        "newState": "RUNNING",
                        "currentValue": 10
                    }
                ],
                "owner": {
                    "createdBy": "user",
                    "project": null
                },
                "permissions": {
                    "myself": [
                        "ADMIN"
                    ],
                    "others": [
                    ]
                }
            }
        ]
    }
);

/*
HttpStatusCode(value=500, description=Internal Server Error)
*/

/* In this case, imagine that the provider failed to create the second resource. This should
immediately trigger cleanup on the provider, if the first resource was already created. The provider
should then respond with an appropriate error message. Providers should not attempt to only
partially create the resources. */
Communication Flow: Curl
# ------------------------------------------------------------------------------------------------------
# $host is the UCloud instance to contact. Example: 'http://localhost:8080' or 'https://cloud.sdu.dk'
# $accessToken is a valid access-token issued by UCloud
# ------------------------------------------------------------------------------------------------------

# In this example, we will discover how a provider should deal with a partial failure.

# Authenticated as ucloud
curl -XPOST -H "Authorization: Bearer $accessToken" -H "Content-Type: content-type: application/json; charset=utf-8" "$host/ucloud/PROVIDERID/example" -d '{
    "items": [
        {
            "id": "1234",
            "specification": {
                "start": 0,
                "target": 100,
                "product": {
                    "id": "example-compute",
                    "category": "example-compute",
                    "provider": "example"
                }
            },
            "createdAt": 1635170395571,
            "status": {
                "state": "RUNNING",
                "value": 10,
                "resolvedSupport": null,
                "resolvedProduct": null
            },
            "updates": [
                {
                    "timestamp": 1635170395571,
                    "status": "We are about to start counting!",
                    "newState": "PENDING",
                    "currentValue": null
                },
                {
                    "timestamp": 1635170395571,
                    "status": "We are now counting!",
                    "newState": "RUNNING",
                    "currentValue": 10
                }
            ],
            "owner": {
                "createdBy": "user",
                "project": null
            },
            "permissions": {
                "myself": [
                    "ADMIN"
                ],
                "others": [
                ]
            }
        },
        {
            "id": "51214",
            "specification": {
                "start": 0,
                "target": 100,
                "product": {
                    "id": "example-compute",
                    "category": "example-compute",
                    "provider": "example"
                }
            },
            "createdAt": 1635170395571,
            "status": {
                "state": "RUNNING",
                "value": 10,
                "resolvedSupport": null,
                "resolvedProduct": null
            },
            "updates": [
                {
                    "timestamp": 1635170395571,
                    "status": "We are about to start counting!",
                    "newState": "PENDING",
                    "currentValue": null
                },
                {
                    "timestamp": 1635170395571,
                    "status": "We are now counting!",
                    "newState": "RUNNING",
                    "currentValue": 10
                }
            ],
            "owner": {
                "createdBy": "user",
                "project": null
            },
            "permissions": {
                "myself": [
                    "ADMIN"
                ],
                "others": [
                ]
            }
        }
    ]
}'


# HttpStatusCode(value=500, description=Internal Server Error)

# In this case, imagine that the provider failed to create the second resource. This should
# immediately trigger cleanup on the provider, if the first resource was already created. The provider
# should then respond with an appropriate error message. Providers should not attempt to only
# partially create the resources.
Communication Flow: Visual