diff --git a/CreateService/__tests__/handler.test.ts b/CreateService/__tests__/handler.test.ts index d284f55f..f284916f 100644 --- a/CreateService/__tests__/handler.test.ts +++ b/CreateService/__tests__/handler.test.ts @@ -1,9 +1,5 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable sonar/sonar-max-lines-per-function */ - -import * as df from "durable-functions"; -import * as lolex from "lolex"; - import * as TE from "fp-ts/lib/TaskEither"; import { toCosmosErrorResponse } from "@pagopa/io-functions-commons/dist/src/utils/cosmosdb_model"; import { @@ -12,21 +8,8 @@ import { aSeralizedService, aServicePayload } from "../../__mocks__/mocks"; -import { UpsertServiceEvent } from "../../utils/UpsertServiceEvent"; import { CreateServiceHandler } from "../handler"; -// eslint-disable-next-line functional/no-let -let clock: lolex.InstalledClock; - -beforeEach(() => { - (df.getClient as any).mockClear(); - (df as any).mockStartNew.mockClear(); - clock = lolex.install({ now: Date.now() }); -}); -afterEach(() => { - clock.uninstall(); -}); - describe("CreateServiceHandler", () => { it("should return a query error if the service fails to be created", async () => { const mockServiceModel = { @@ -70,39 +53,4 @@ describe("CreateServiceHandler", () => { expect(response.value).toEqual(aSeralizedService); } }); - - it("should start the orchestrator with an appropriate event after the service is created", async () => { - const mockServiceModel = { - create: jest.fn(_ => { - return TE.right(aRetrievedService); - }) - }; - - const contextMock = { - log: jest.fn() - }; - - const createServiceHandler = CreateServiceHandler(mockServiceModel as any); - - await createServiceHandler( - contextMock as any, // Not used - undefined as any, // Not used - aServicePayload - ); - - const upsertServiceEvent = UpsertServiceEvent.encode({ - newService: aRetrievedService, - updatedAt: new Date() - }); - - expect(df.getClient).toHaveBeenCalledTimes(1); - - const dfClient = df.getClient(contextMock); - expect(dfClient.startNew).toHaveBeenCalledTimes(1); - expect(dfClient.startNew).toHaveBeenCalledWith( - "UpsertServiceOrchestrator", - undefined, - upsertServiceEvent - ); - }); }); diff --git a/CreateService/handler.ts b/CreateService/handler.ts index 1e94be1e..e4c87f29 100644 --- a/CreateService/handler.ts +++ b/CreateService/handler.ts @@ -2,8 +2,6 @@ import { Context } from "@azure/functions"; import * as express from "express"; -import * as df from "durable-functions"; - import { isLeft } from "fp-ts/lib/Either"; import { @@ -34,7 +32,6 @@ import { retrievedServiceToApiService } from "../utils/conversions"; import { ServicePayloadMiddleware } from "../utils/middlewares/service"; -import { UpsertServiceEvent } from "../utils/UpsertServiceEvent"; type ICreateServiceHandler = ( context: Context, @@ -65,22 +62,9 @@ export function CreateServiceHandler( ); } - const createdService = errorOrCreatedService.right; - - const upsertServiceEvent = UpsertServiceEvent.encode({ - newService: createdService, - updatedAt: new Date() - }); - - // Start orchestrator - const dfClient = df.getClient(context); - await dfClient.startNew( - "UpsertServiceOrchestrator", - undefined, - upsertServiceEvent + return ResponseSuccessJson( + retrievedServiceToApiService(errorOrCreatedService.right) ); - - return ResponseSuccessJson(retrievedServiceToApiService(createdService)); }; } diff --git a/UpdateService/__tests__/handler.test.ts b/UpdateService/__tests__/handler.test.ts index e3fbdb07..c27c6363 100644 --- a/UpdateService/__tests__/handler.test.ts +++ b/UpdateService/__tests__/handler.test.ts @@ -1,9 +1,6 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable sonar/sonar-max-lines-per-function */ -import * as df from "durable-functions"; -import * as lolex from "lolex"; - import { ServiceId } from "@pagopa/io-functions-commons/dist/generated/definitions/ServiceId"; import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; @@ -16,7 +13,6 @@ import { aServicePayload } from "../../__mocks__/mocks"; import { apiServiceToService } from "../../utils/conversions"; -import { UpsertServiceEvent } from "../../utils/UpsertServiceEvent"; import { UpdateServiceHandler } from "../handler"; const aDepartmentName = "UpdateDept" as NonEmptyString; @@ -29,16 +25,8 @@ const leftErrorFn = jest.fn(() => { return TE.left(toCosmosErrorResponse({ kind: "COSMOS_ERROR_RESPONSE" })); }); -// eslint-disable-next-line functional/no-let -let clock: lolex.InstalledClock; beforeEach(() => { - (df.getClient as any).mockClear(); - (df as any).mockStartNew.mockClear(); - clock = lolex.install({ now: Date.now() }); - leftErrorFn.mockClear(); -}); -afterEach(() => { - clock.uninstall(); + jest.clearAllMocks(); }); describe("UpdateServiceHandler", () => { @@ -187,50 +175,4 @@ describe("UpdateServiceHandler", () => { }); } }); - - it("should start the orchestrator with an appropriate event after the service is updated", async () => { - const serviceModelMock = { - findOneByServiceId: jest.fn(() => { - return TE.right(O.some(aRetrievedService)); - }), - update: jest.fn(() => - TE.right({ - ...aRetrievedService, - ...anUpdatedApiService - }) - ) - }; - - const contextMock = { - log: jest.fn() - }; - - const updateServiceHandler = UpdateServiceHandler(serviceModelMock as any); - - await updateServiceHandler( - contextMock as any, // Not used - undefined as any, // Not used - aServicePayload.service_id, - { - ...aServicePayload, - department_name: aDepartmentName - } - ); - - const upsertServiceEvent = UpsertServiceEvent.encode({ - newService: { ...aRetrievedService, departmentName: aDepartmentName }, - oldService: aRetrievedService, - updatedAt: new Date() - }); - - expect(df.getClient).toHaveBeenCalledTimes(1); - - const dfClient = df.getClient(contextMock); - expect(dfClient.startNew).toHaveBeenCalledTimes(1); - expect(dfClient.startNew).toHaveBeenCalledWith( - "UpsertServiceOrchestrator", - undefined, - upsertServiceEvent - ); - }); }); diff --git a/UpdateService/handler.ts b/UpdateService/handler.ts index 4fb0fe46..f21f853d 100644 --- a/UpdateService/handler.ts +++ b/UpdateService/handler.ts @@ -2,8 +2,6 @@ import { Context } from "@azure/functions"; import * as express from "express"; -import * as df from "durable-functions"; - import * as E from "fp-ts/lib/Either"; import * as O from "fp-ts/lib/Option"; @@ -41,7 +39,6 @@ import { } from "../utils/conversions"; import { ServicePayloadMiddleware } from "../utils/middlewares/service"; import { ServiceIdMiddleware } from "../utils/middlewares/serviceid"; -import { UpsertServiceEvent } from "../utils/UpsertServiceEvent"; type IUpdateServiceHandler = ( context: Context, @@ -102,23 +99,9 @@ export function UpdateServiceHandler( ); } - const updatedService = errorOrUpdatedService.right; - - const upsertServiceEvent = UpsertServiceEvent.encode({ - newService: updatedService, - oldService: existingService, - updatedAt: new Date() - }); - - // Start orchestrator - const dfClient = df.getClient(context); - await dfClient.startNew( - "UpsertServiceOrchestrator", - undefined, - upsertServiceEvent + return ResponseSuccessJson( + retrievedServiceToApiService(errorOrUpdatedService.right) ); - - return ResponseSuccessJson(retrievedServiceToApiService(updatedService)); }; } diff --git a/UpdateVisibleServicesActivity/function.json b/UpdateVisibleServicesActivity/function.json deleted file mode 100644 index 256c63a3..00000000 --- a/UpdateVisibleServicesActivity/function.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "bindings": [ - { - "name": "name", - "type": "activityTrigger", - "direction": "in" - } - ], - "scriptFile": "../dist/UpdateVisibleServicesActivity/index.js" -} diff --git a/UpdateVisibleServicesActivity/handler.ts b/UpdateVisibleServicesActivity/handler.ts deleted file mode 100644 index 458f93eb..00000000 --- a/UpdateVisibleServicesActivity/handler.ts +++ /dev/null @@ -1,237 +0,0 @@ -import { Context } from "@azure/functions"; -import { BlobService } from "azure-storage"; - -import * as t from "io-ts"; - -import * as E from "fp-ts/lib/Either"; -import * as O from "fp-ts/lib/Option"; - -import { Second } from "@pagopa/ts-commons/lib/units"; - -import { ServiceId } from "@pagopa/io-functions-commons/dist/generated/definitions/ServiceId"; -import { - VISIBLE_SERVICE_BLOB_ID, - VISIBLE_SERVICE_CONTAINER, - VisibleService -} from "@pagopa/io-functions-commons/dist/src/models/visible_service"; -import { - acquireLease, - getBlobAsObject, - releaseLease, - upsertBlobFromObject -} from "@pagopa/io-functions-commons/dist/src/utils/azure_storage"; -import { flow, pipe } from "fp-ts/lib/function"; - -// The lease duration in seconds. -// After the retrive/update activities the lease is released actively by the function. -// If the function crashes the lease is released by the system. -const LEASE_DURATION = 15 as Second; - -const AddVisibleServiceInput = t.interface({ - action: t.literal("UPSERT"), - visibleService: VisibleService -}); - -const RemoveVisibleServiceInput = t.interface({ - action: t.literal("DELETE"), - visibleService: VisibleService -}); - -export const Input = t.taggedUnion("action", [ - AddVisibleServiceInput, - RemoveVisibleServiceInput -]); - -export type Input = t.TypeOf; - -const ResultSuccess = t.interface({ - kind: t.literal("SUCCESS") -}); - -const ResultFailure = t.interface({ - kind: t.literal("FAILURE"), - reason: t.string -}); - -export const Result = t.taggedUnion("kind", [ResultSuccess, ResultFailure]); - -export type Result = t.TypeOf; - -const VisibleServicesBlob = t.dictionary(ServiceId, VisibleService); - -interface IVisibleServices { - readonly [key: string]: VisibleService; -} - -/** - * Create new visibleServices - * - * @param visibleServices The current visibleServices - * @param visibleService The visible service to add/remove - * @param action The UPSERT/DELETE action - */ -// eslint-disable-next-line prefer-arrow/prefer-arrow-functions -function computeNewVisibleServices( - visibleServices: IVisibleServices, - visibleService: VisibleService, - action: Input["action"] -): O.Option { - // Get the current visible service if available - const currentVisibleService = visibleServices[visibleService.serviceId]; - if ( - currentVisibleService !== undefined && - currentVisibleService.version >= visibleService.version - ) { - // A newer version is already stored in the blob, so skip the remove/update - return O.none; - } - if (action === "DELETE") { - const { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - [visibleService.serviceId]: deletedVisibleService, - ...restVisibleServices - } = visibleServices; - - return O.some(restVisibleServices); - } - - return O.some({ - ...visibleServices, - [visibleService.serviceId]: visibleService - }); -} - -/** - * Update visibleServices blob adding/removing the visible service. - * Return an error on failure. - */ -// eslint-disable-next-line prefer-arrow/prefer-arrow-functions -async function updateVisibleServices( - blobService: BlobService, - visibleService: VisibleService, - action: Input["action"], - leaseId: string -): Promise> { - // Retrieve the current visibleServices blob using the leaseId - const errorOrMaybeVisibleServices = await getBlobAsObject( - VisibleServicesBlob, - blobService, - VISIBLE_SERVICE_CONTAINER, - VISIBLE_SERVICE_BLOB_ID, - { - leaseId - } - ); - - // Default to an empty object when the blob does not exist yet - const errorOrVisibleServices = pipe( - errorOrMaybeVisibleServices, - E.chain(flow(E.fromOption(() => ({})))) - ); - - if (E.isLeft(errorOrVisibleServices)) { - return E.left( - Error( - `UpdateVisibleServicesActivity|Cannot decode blob|ERROR=${errorOrVisibleServices.left}` - ) - ); - } - - // Compute the new visibleServices blob content - const maybeNewVisibleServices = computeNewVisibleServices( - errorOrVisibleServices.right, - visibleService, - action - ); - - if (O.isSome(maybeNewVisibleServices)) { - const newVisibleServices = maybeNewVisibleServices.value; - // Store the new visibleServices blob - const errorOrBlobResult = await upsertBlobFromObject( - blobService, - VISIBLE_SERVICE_CONTAINER, - VISIBLE_SERVICE_BLOB_ID, - newVisibleServices, - { - leaseId - } - ); - - if (E.isLeft(errorOrBlobResult)) { - return E.left( - Error( - `UpdateVisibleServicesActivity|Cannot save blob|ERROR=${errorOrBlobResult.left.message}` - ) - ); - } - } - - return E.right(true); -} - -/** - * Returns a function for handling UpdateVisibleServicesActivity - */ -export const getUpdateVisibleServicesActivityHandler = ( - blobService: BlobService -) => async (context: Context, input: unknown): Promise => { - const errorOrInput = Input.decode(input); - - if (E.isLeft(errorOrInput)) { - // Return a failure result - // We don't throw an exception because is not possible to retry - return Result.encode({ - kind: "FAILURE", - reason: "Cannot parse input" - }); - } - - const { action, visibleService } = errorOrInput.right; - - // Lock the blob to avoid concurrency problems - const errorOrLeaseResult = await acquireLease( - blobService, - VISIBLE_SERVICE_CONTAINER, - VISIBLE_SERVICE_BLOB_ID, - { - leaseDuration: LEASE_DURATION - } - ); - - if (E.isLeft(errorOrLeaseResult)) { - // Another instance of this activity has locked the blob we need to retry - const error = Error( - `UpdateVisibleServicesActivity|Cannot acquire the lease on the blob|ERROR=${errorOrLeaseResult.left}` - ); - context.log.error(error.message); - throw error; - } - - const leaseResult = errorOrLeaseResult.right; - - const errorOrOk = await updateVisibleServices( - blobService, - visibleService, - action, - leaseResult.id - ); - - // Release the lock - await releaseLease( - blobService, - VISIBLE_SERVICE_CONTAINER, - VISIBLE_SERVICE_BLOB_ID, - leaseResult.id - ); - - if (E.isLeft(errorOrOk)) { - context.log.error(errorOrOk.left.message); - // Throw an error so the activity is retried - throw errorOrOk.left; - } - - // Return a success result - return Result.encode({ - kind: "SUCCESS" - }); -}; diff --git a/UpdateVisibleServicesActivity/index.ts b/UpdateVisibleServicesActivity/index.ts deleted file mode 100644 index 4d96de9a..00000000 --- a/UpdateVisibleServicesActivity/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { createBlobService } from "azure-storage"; -import { getConfigOrThrow } from "../utils/config"; -import { getUpdateVisibleServicesActivityHandler } from "./handler"; - -const config = getConfigOrThrow(); -const storageConnectionString = config.StorageConnection; -const blobService = createBlobService(storageConnectionString); - -const activityFunctionHandler = getUpdateVisibleServicesActivityHandler( - blobService -); - -export default activityFunctionHandler; diff --git a/UpdateVisibleServicesCache/__test__/index.test.ts b/UpdateVisibleServicesCache/__test__/index.test.ts deleted file mode 100644 index 3a2c1f36..00000000 --- a/UpdateVisibleServicesCache/__test__/index.test.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { Context } from "@azure/functions"; -import { index as updateVisibleServiceCache } from "../index"; - -const mockContext = (input: unknown): Context => - (({ - bindings: { - visibleServicesBlob: input - }, - log: console - } as unknown) as Context); - -describe("UpdateVisibleServiceCache", () => { - it.each` - scenario | input | visibleServicesCacheBlob | visibleServicesByScopeCacheBlob - ${"on empty input"} | ${{}} | ${{ items: [] }} | ${{ LOCAL: [], NATIONAL: [] }} - `( - "should succeed $title", - async ({ - input, - visibleServicesCacheBlob, - visibleServicesByScopeCacheBlob - }) => { - const context = mockContext(input); - - await updateVisibleServiceCache(context); - - expect(context.bindings.visibleServicesCacheBlob).toEqual( - visibleServicesCacheBlob - ); - expect(context.bindings.visibleServicesByScopeCacheBlob).toEqual( - visibleServicesByScopeCacheBlob - ); - } - ); - - it.each` - scenario | input - ${"on invalid input"} | ${"not-a-valid-input"} - `("should fail $title", async ({ input }) => { - const context = mockContext(input); - - await updateVisibleServiceCache(context); - - // out bindings aren't used - expect(context.bindings.visibleServicesCacheBlob).toBe(undefined); - expect(context.bindings.visibleServicesByScopeCacheBlob).toBe(undefined); - }); -}); diff --git a/UpdateVisibleServicesCache/function.json b/UpdateVisibleServicesCache/function.json deleted file mode 100644 index 90581ccc..00000000 --- a/UpdateVisibleServicesCache/function.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "disabled": false, - "bindings": [ - { - "schedule": "0 0 * * * *", - "name": "updateVisibleServiceCacheTimer", - "type": "timerTrigger", - "direction": "in" - }, - { - "name": "starter", - "type": "orchestrationClient", - "direction": "in" - }, - { - "name": "visibleServicesBlob", - "type": "blob", - "path": "cached/visible-services.json", - "connection": "StorageConnection", - "direction": "in" - }, - { - "name": "visibleServicesCacheBlob", - "type": "blob", - "path": "services/visible-services.json", - "connection": "AssetsStorageConnection", - "direction": "out" - }, - { - "name": "visibleServicesByScopeCacheBlob", - "type": "blob", - "path": "services/visible-services-by-scope.json", - "connection": "AssetsStorageConnection", - "direction": "out" - } - ], - "scriptFile": "../dist/UpdateVisibleServicesCache/index.js" -} diff --git a/UpdateVisibleServicesCache/index.ts b/UpdateVisibleServicesCache/index.ts deleted file mode 100644 index 46e104fe..00000000 --- a/UpdateVisibleServicesCache/index.ts +++ /dev/null @@ -1,94 +0,0 @@ -/** - * This time triggered function creates a cache for visible services: - * - * - read the cached visible-service.json (input binding) - * - create a version of services/visible-services.json suitable to be consumed by the mobile APP - * - put the generated JSON into the assets storage (which is reachable behind the CDN) - * - loop on visible services and store services/.json (output binding) - * - * The tuple stored is (serviceId, version, scope). - * - * TODO: delete blobs for services that aren't visible anymore. - */ -import { Context } from "@azure/functions"; - -import { isLeft } from "fp-ts/lib/Either"; -import * as S from "fp-ts/lib/string"; -import * as RM from "fp-ts/lib/ReadonlyMap"; -import { VisibleService } from "@pagopa/io-functions-commons/dist/src/models/visible_service"; - -import * as df from "durable-functions"; -import * as t from "io-ts"; -import { pipe } from "fp-ts/lib/function"; - -export type VisibleServices = t.TypeOf; -export const VisibleServices = t.record(t.string, VisibleService); - -// eslint-disable-next-line prefer-arrow/prefer-arrow-functions -async function UpdateVisibleServiceCache(context: Context): Promise { - const errorOrVisibleServices = VisibleServices.decode( - context.bindings.visibleServicesBlob - ); - - if (isLeft(errorOrVisibleServices)) { - context.log.info( - "UpdateVisibleServiceCache|Cannot decode visible services" - ); - return; - } - - const visibleServiceJson = errorOrVisibleServices.right; - const visibleServices = RM.fromMap( - new Map(Object.entries(visibleServiceJson)) - ); - - const visibleServicesTuples = pipe( - visibleServices, - RM.map(v => ({ - scope: v.serviceMetadata ? v.serviceMetadata.scope : undefined, - service_id: v.serviceId, - version: v.version - })) - ); - - // store visible services in the blob - // eslint-disable-next-line functional/immutable-data - context.bindings.visibleServicesCacheBlob = { - items: pipe( - visibleServicesTuples, - RM.reduce(S.Ord)([], (p, c) => [...p, c]) - ) - }; - - const { left: NATIONAL, right: LOCAL } = pipe( - visibleServices, - RM.partition(s => s.serviceMetadata && s.serviceMetadata.scope === "LOCAL") - ); - - // store visible services partitioned by scope - // eslint-disable-next-line functional/immutable-data - context.bindings.visibleServicesByScopeCacheBlob = { - LOCAL: pipe( - LOCAL, - RM.map(_ => _.serviceId), - RM.reduce(S.Ord)([], (p, c) => [...p, c]) - ), - NATIONAL: pipe( - NATIONAL, - RM.map(_ => _.serviceId), - RM.reduce(S.Ord)([], (p, c) => [...p, c]) - ) - }; - - // start orchestrator to loop on every visible service - // and to store it in a blob - await df - .getClient(context) - .startNew( - "UpdateVisibleServicesCacheOrchestrator", - undefined, - visibleServiceJson - ); -} - -export { UpdateVisibleServiceCache as index }; diff --git a/UpdateVisibleServicesCacheActivity/function.json b/UpdateVisibleServicesCacheActivity/function.json deleted file mode 100644 index 927200b5..00000000 --- a/UpdateVisibleServicesCacheActivity/function.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "disabled": false, - "bindings": [ - { - "name": "visibleServiceJson", - "type": "activityTrigger", - "direction": "in" - }, - { - "name": "visibleServiceCacheBlob", - "type": "blob", - "path": "services/{serviceId}.json", - "connection": "AssetsStorageConnection", - "direction": "out" - } - ], - "scriptFile": "../dist/UpdateVisibleServicesCacheActivity/index.js" -} diff --git a/UpdateVisibleServicesCacheActivity/index.ts b/UpdateVisibleServicesCacheActivity/index.ts deleted file mode 100644 index ca7f012b..00000000 --- a/UpdateVisibleServicesCacheActivity/index.ts +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Take service json as input and store the JSON into - * services/.json through output binding. - */ -import { Context } from "@azure/functions"; -import * as E from "fp-ts/lib/Either"; -import { - toServicePublic, - VisibleService -} from "@pagopa/io-functions-commons/dist/src/models/visible_service"; - -// eslint-disable-next-line prefer-arrow/prefer-arrow-functions -async function UpdateVisibleServiceCacheActivity( - context: Context -): Promise { - const visibleServiceJson = context.bindings.visibleServiceJson; - const errorOrVisibleService = VisibleService.decode(visibleServiceJson); - - if (E.isLeft(errorOrVisibleService)) { - context.log.error( - "UpdateVisibleServiceCacheActivity|Cannot decode visible service JSON" - ); - return; - } - const visibleService = errorOrVisibleService.right; - - context.log.info( - "UpdateVisibleServiceCacheActivity|SERVICE_ID=", - visibleService.serviceId - ); - // we don't want to pollute the table storage - // (where the activity result is saved), - // so we return void from this method and - // use context bindings - // eslint-disable-next-line functional/immutable-data - context.bindings.visibleServiceCacheBlob = toServicePublic(visibleService); -} - -export default UpdateVisibleServiceCacheActivity; diff --git a/UpdateVisibleServicesCacheOrchestrator/function.json b/UpdateVisibleServicesCacheOrchestrator/function.json deleted file mode 100644 index d4af1dd3..00000000 --- a/UpdateVisibleServicesCacheOrchestrator/function.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "disabled": false, - "bindings": [ - { - "name": "context", - "type": "orchestrationTrigger", - "direction": "in" - } - ], - "scriptFile": "../dist/UpdateVisibleServicesCacheOrchestrator/index.js" -} - diff --git a/UpdateVisibleServicesCacheOrchestrator/index.ts b/UpdateVisibleServicesCacheOrchestrator/index.ts deleted file mode 100644 index 7fd53f77..00000000 --- a/UpdateVisibleServicesCacheOrchestrator/index.ts +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Calls an activity function for each visible service - * found into the stored JSON. The activity function will store - * one JSON into the blob storage for each visible service found. - */ - -import { - IOrchestrationFunctionContext, - Task -} from "durable-functions/lib/src/classes"; - -import * as df from "durable-functions"; -import * as E from "fp-ts/lib/Either"; -import { VisibleServices } from "../UpdateVisibleServicesCache"; - -const UpdateVisibleServicesCacheOrchestrator = df.orchestrator(function*( - context: IOrchestrationFunctionContext -): Generator { - const visibleServicesJson = context.df.getInput(); - const errorOrVisibleServices = VisibleServices.decode(visibleServicesJson); - - if (E.isLeft(errorOrVisibleServices)) { - context.log.error( - "UpdateVisibleServicesCacheOrchestrator|Error decoding visible services JSON." - ); - return; - } - const visibleServices = errorOrVisibleServices.right; - - for (const visibleServiceId of Object.keys(visibleServices)) { - yield context.df.callActivity( - "UpdateVisibleServicesCacheActivity", - visibleServices[visibleServiceId] - ); - } -}); - -export default UpdateVisibleServicesCacheOrchestrator; diff --git a/UpsertServiceOrchestrator/function.json b/UpsertServiceOrchestrator/function.json deleted file mode 100644 index 034adcb8..00000000 --- a/UpsertServiceOrchestrator/function.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "bindings": [ - { - "name": "context", - "type": "orchestrationTrigger", - "direction": "in" - } - ], - "scriptFile": "../dist/UpsertServiceOrchestrator/index.js" -} diff --git a/UpsertServiceOrchestrator/handler.ts b/UpsertServiceOrchestrator/handler.ts deleted file mode 100644 index 4d1ff4ed..00000000 --- a/UpsertServiceOrchestrator/handler.ts +++ /dev/null @@ -1,133 +0,0 @@ -import * as df from "durable-functions"; - -import { IOrchestrationFunctionContext } from "durable-functions/lib/src/classes"; - -import * as E from "fp-ts/lib/Either"; -import { isSome, none, Option, some } from "fp-ts/lib/Option"; - -import { readableReport } from "@pagopa/ts-commons/lib/reporters"; - -import { RetrievedService } from "@pagopa/io-functions-commons/dist/src/models/service"; - -import { - Input as UpdateVisibleServicesActivityInput, - Result as UpdateVisibleServicesActivityResult -} from "../UpdateVisibleServicesActivity/handler"; -import { retrievedServiceToVisibleService } from "../utils/conversions"; -import { UpsertServiceEvent } from "../utils/UpsertServiceEvent"; - -/** - * Using the data of new and old service calculate the action to perform to the visible services - */ -// eslint-disable-next-line prefer-arrow/prefer-arrow-functions -function computeMaybeAction( - newService: RetrievedService, - oldService?: RetrievedService -): Option { - if (oldService === undefined) { - // A service has been created - return newService.isVisible ? some("UPSERT") : none; - } - - // A service has been update - - // Visibility not changed - if (oldService.isVisible === newService.isVisible) { - return newService.isVisible ? some("UPSERT") : none; - } - - // Visibility changed - // If the old service was NOT visible and the new service IS visible return UPSERT, return DELETE otherwise - return !oldService.isVisible && newService.isVisible - ? some("UPSERT") - : some("DELETE"); -} - -export const handler = function*( - context: IOrchestrationFunctionContext -): Generator { - const input = context.df.getInput(); - - const retryOptions = new df.RetryOptions(5000, 10); - // eslint-disable-next-line functional/immutable-data - retryOptions.backoffCoefficient = 1.5; - - // Check if input is valid - const errorOrUpsertServiceEvent = UpsertServiceEvent.decode(input); - - if (E.isLeft(errorOrUpsertServiceEvent)) { - context.log.error( - `UpdateVisibleServicesActivity|Cannot parse input|ERROR=${readableReport( - errorOrUpsertServiceEvent.left - )}` - ); - // We will never be able to recover from this, so don't trigger a retry - return []; - } - - const upsertServiceEvent = errorOrUpsertServiceEvent.right; - const { newService, oldService } = upsertServiceEvent; - - // Update visible services if needed - const maybeAction = computeMaybeAction(newService, oldService); - const visibleService = retrievedServiceToVisibleService(newService); - if (isSome(maybeAction)) { - const action = maybeAction.value; - context.log.verbose( - `UpdateVisibleServicesActivity|Visible services must be updated|SERVICE_ID=${visibleService.serviceId}|ACTION=${action}` - ); - const updateVisibleServicesActivityInput = UpdateVisibleServicesActivityInput.encode( - { - action, - visibleService - } - ); - - try { - const updateVisibleServicesActivityResultJson = yield context.df.callActivityWithRetry( - "UpdateVisibleServicesActivity", - retryOptions, - updateVisibleServicesActivityInput - ); - - const errorOrUpdateVisibleServicesActivityResult = UpdateVisibleServicesActivityResult.decode( - updateVisibleServicesActivityResultJson - ); - - if (E.isLeft(errorOrUpdateVisibleServicesActivityResult)) { - context.log.error( - `UpdateVisibleServicesActivity|Can't decode result|SERVICE_ID=${ - visibleService.serviceId - }|ERROR=${readableReport( - errorOrUpdateVisibleServicesActivityResult.left - )}` - ); - - return []; - } - - const updateVisibleServicesActivityResult = - errorOrUpdateVisibleServicesActivityResult.right; - - if (updateVisibleServicesActivityResult.kind === "SUCCESS") { - context.log.verbose( - `UpdateVisibleServicesActivity|Update success|SERVICE_ID=${visibleService.serviceId}|ACTION=${action}` - ); - } else { - context.log.error( - `UpdateVisibleServicesActivity|Activity failure|SERVICE_ID=${visibleService.serviceId}|ERROR=${updateVisibleServicesActivityResult.reason}` - ); - } - } catch (e) { - context.log.error( - `UpdateVisibleServicesActivity|Max retry exceeded|SERVICE_ID=${visibleService.serviceId}|ERROR=${e}` - ); - } - } else { - context.log.verbose( - `UpdateVisibleServicesActivity|No need to update visible services|SERVICE_ID=${visibleService.serviceId}` - ); - } - - return []; -}; diff --git a/UpsertServiceOrchestrator/index.ts b/UpsertServiceOrchestrator/index.ts deleted file mode 100644 index d7b45ae0..00000000 --- a/UpsertServiceOrchestrator/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -import * as df from "durable-functions"; - -import { handler } from "./handler"; - -const orchestrator = df.orchestrator(handler); - -export default orchestrator; diff --git a/package.json b/package.json index de72f131..a54d43f4 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,6 @@ "@types/documentdb": "^1.10.8", "@types/express": "^4.17.12", "@types/jest": "^24.9.1", - "@types/lolex": "^5.1.0", "@types/upng-js": "^2.1.1", "auto-changelog": "^2.3.0", "azurite": "^3.13.1", @@ -46,7 +45,6 @@ "fast-check": "^1.26.0", "jest": "^24.9.0", "jest-mock-express": "^0.1.1", - "lolex": "^5.1.2", "marked": "^3.0.2", "modclean": "^3.0.0-beta.1", "npm-run-all": "^4.1.5", diff --git a/utils/UpsertServiceEvent.ts b/utils/UpsertServiceEvent.ts deleted file mode 100644 index 285ea78a..00000000 --- a/utils/UpsertServiceEvent.ts +++ /dev/null @@ -1,23 +0,0 @@ -import * as t from "io-ts"; - -import { UTCISODateFromString } from "@pagopa/ts-commons/lib/dates"; - -import { RetrievedService } from "@pagopa/io-functions-commons/dist/src/models/service"; - -/** - * Carries information about created or updated service. - * - * When oldService is defined, the service has been updated, or it has been - * created otherwise. - */ -export const UpsertServiceEvent = t.intersection([ - t.interface({ - newService: RetrievedService, - updatedAt: UTCISODateFromString - }), - t.partial({ - oldService: RetrievedService - }) -]); - -export type UpsertServiceEvent = t.TypeOf; diff --git a/utils/conversions.ts b/utils/conversions.ts index 105e30e7..12498e89 100644 --- a/utils/conversions.ts +++ b/utils/conversions.ts @@ -12,7 +12,6 @@ import { toAuthorizedCIDRs, toAuthorizedRecipients } from "@pagopa/io-functions-commons/dist/src/models/service"; -import { VisibleService } from "@pagopa/io-functions-commons/dist/src/models/visible_service"; import { CosmosErrors } from "@pagopa/io-functions-commons/dist/src/utils/cosmosdb_model"; import { toApiServiceMetadata as toServiceMetadata } from "@pagopa/io-functions-commons/dist/src/utils/service_metadata"; import { Errors } from "io-ts"; @@ -150,34 +149,6 @@ export function retrievedServiceToApiService( } as ApiService; } -// eslint-disable-next-line prefer-arrow/prefer-arrow-functions -export function retrievedServiceToVisibleService( - retrievedService: RetrievedService -): VisibleService { - const { - departmentName, - id, - organizationFiscalCode, - organizationName, - requireSecureChannels, - serviceId, - serviceMetadata, - serviceName, - version - } = retrievedService; - return { - departmentName, - id, - organizationFiscalCode, - organizationName, - requireSecureChannels, - serviceId, - serviceMetadata, - serviceName, - version - }; -} - // eslint-disable-next-line prefer-arrow/prefer-arrow-functions export function userContractToApiUser( user: UserContract diff --git a/yarn.lock b/yarn.lock index 3b3af3dc..821e01c5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1025,13 +1025,6 @@ "@sendgrid/client" "^6.5.5" "@sendgrid/helpers" "^6.5.5" -"@sinonjs/commons@^1.7.0": - version "1.8.3" - resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d" - integrity sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ== - dependencies: - type-detect "4.0.8" - "@tootallnate/once@1": version "1.1.2" resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" @@ -1168,11 +1161,6 @@ resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.172.tgz#aad774c28e7bfd7a67de25408e03ee5a8c3d028a" integrity sha512-/BHF5HAx3em7/KkzVKm3LrsD6HZAXuXO1AJZQ3cRRBZj4oHZDviWPYu0aEplAqDFNHZPW6d3G7KN+ONcCCC7pw== -"@types/lolex@^5.1.0": - version "5.1.1" - resolved "https://registry.yarnpkg.com/@types/lolex/-/lolex-5.1.1.tgz#86799c00c8d0b75e4e45dcb6befb79932e9ea3f6" - integrity sha512-FqJj5xmnDe/RBy9jt0c6dybENYXS0A5Wdt0e1OsG6m+KDCMx2SmY7OobTBQ6jqIqaA6yvIiCjbPET/zn7cx12g== - "@types/mime@^1": version "1.3.2" resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" @@ -6800,13 +6788,6 @@ lokijs@^1.5.6: resolved "https://registry.yarnpkg.com/lokijs/-/lokijs-1.5.12.tgz#cb55b37009bdf09ee7952a6adddd555b893653a0" integrity sha512-Q5ALD6JiS6xAUWCwX3taQmgwxyveCtIIuL08+ml0nHwT3k0S/GIFJN+Hd38b1qYIMaE5X++iqsqWVksz7SYW+Q== -lolex@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/lolex/-/lolex-5.1.2.tgz#953694d098ce7c07bc5ed6d0e42bc6c0c6d5a367" - integrity sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A== - dependencies: - "@sinonjs/commons" "^1.7.0" - long@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" @@ -9840,11 +9821,6 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" -type-detect@4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" - integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== - type-fest@^0.20.2: version "0.20.2" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"