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

"No job functions found" - model v4 - TypeScript - Not recognizing existing functions #3508

Closed
EnderGamingFilms opened this issue Oct 30, 2023 · 8 comments

Comments

@EnderGamingFilms
Copy link

EnderGamingFilms commented Oct 30, 2023

Hello all. I have set up a function app using v4 for nodeJS (TypeScript) and everything has worked fine until today when I was setting up some new environments. I am currently unable to run my v4 functions for some reason. I have tried following the v4 upgrade guide to try and diagnose the issue. In short, this did not work.

I have tried running npm run start as well as building the project and then func start however each mother yields the same result.

  • Core Tools Version: 4.0.5441
  • Extension Bundle Version: [3.*, 4.0.0)
  • Package @azure/functions: ^4.0.0

Here is the console error that is given with either command:

PS C:\Azure\myapp> func start
Can't determine project language from files. Please use one of [--csharp, --javascript, --typescript, --java, --python, --powershell, --custom]
Can't determine project language from files. Please use one of [--csharp, --javascript, --typescript, --java, --python, --powershell, --custom]
Can't determine project language from files. Please use one of [--csharp, --javascript, --typescript, --java, --python, --powershell, --custom]

Azure Functions Core Tools
Core Tools Version:       4.0.5441 Commit hash: N/A  (64-bit)
Function Runtime Version: 4.25.3.21264

Can't determine project language from files. Please use one of [--csharp, --javascript, --typescript, --java, --python, --powershell, --custom]
Can't determine project language from files. Please use one of [--csharp, --javascript, --typescript, --java, --python, --powershell, --custom]
Can't determine project language from files. Please use one of [--csharp, --javascript, --typescript, --java, --python, --powershell, --custom]
[2023-10-30T02:41:44.001Z] No job functions found. Try making your job classes and methods public. If you're using binding extensions (e.g. Azure Storage, ServiceBus, Timers, etc.) make sure you've called the registration method for the extension(s) in your startup code (e.g. builder.AddAzureStorage(), builder.AddServiceBus(), builder.AddTimers(), etc.).
For detailed output, run func with --verbose flag.

And below is my function.

import { app, HttpRequest, HttpResponseInit, InvocationContext } from "@azure/functions";
import Stripe from 'stripe';
import { CosmosClient, ItemResponse } from "@azure/cosmos";
import { Account } from "../../Shared/account";
import { DefaultAzureCredential } from "@azure/identity";

const databaseId: string = process.env['COSMOS_DATABASE'];

export async function CompleteOrder(req: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
    const payload: string = await req.text();
    const sig = req.headers.get('stripe-signature');

    if (typeof sig !== 'string') {
        return {
            status: 400,
            body: `Webhook Error: Missing signature`
        }
    }

    const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
        apiVersion: '2023-08-16',
        typescript: true
    });

    let event;
    try {
        event = stripe.webhooks.constructEvent(payload, sig, process.env.STRIPE_WEBHOOK_SECRET!);
    } catch (err) {
        return {
            status: 400,
            body: `Webhook Error: ${(err as any).message}`
        }
    }

    if (event.type === 'checkout.session.completed') {
        context.log('-- CHECKOUT COMPLETED WEBHOOK --');

        try {
            const session: Stripe.Checkout.Session = event.data.object;
            const client = new CosmosClient(getCredentials());
            const userId: string = session.client_reference_id!;

            context.info(`[READ] Fetching account info >> (userId=${userId})`);

            const accResponse: ItemResponse<Account> = await client
                .database(databaseId)
                .container('Users')
                .item(userId, userId)
                .read<Account>();

            context.trace(`[COST] ${accResponse.requestCharge} RU | Activity Id: ${accResponse.activityId}`);

            if (accResponse.statusCode === 200) {
                const account = accResponse.resource as any;
                const { id, invoice, current_period_end } = account.subscription || {};

                if (current_period_end && current_period_end < Date.now()) {
                    return {
                        status: 200,
                        body: `Subscription is still active under ${id} - ${invoice}, until ${new Date(current_period_end * 1000).toUTCString()}`
                    }
                }
            } else {
                context.error(`[FAILURE] Unable to find account >> (userId=${userId})`);
                return {
                    status: 404,
                    body: `Unable to find account for ${userId}`
                }
            }

            // Ask Stripe for the latest subscription info
            const subscription = await stripe.subscriptions.retrieve(session.subscription! as string);

            context

            const patchSpec: any = [
                {
                    "op": "set",
                    "path": "/subscription",
                    "value": {
                        "id": session.subscription,
                        "invoice": session.invoice,
                        "current_period_end": subscription.current_period_end,
                        "interval": subscription.items.data[0].price.recurring.interval,
                    }
                }
            ];

            context.info(`[UPDATE] Updating account >> (userId=${userId})`);

            const item: ItemResponse<Account> = await client
                .database(databaseId)
                .container('Users')
                .item(userId, userId)
                .patch<Account>(patchSpec);

            context.trace(`[COST] ${item.requestCharge} RU | Activity Id: ${item.activityId}`);

            return {
                status: 200,
                body: 'Hello from completeOrder'
            }
        } catch (err) {
            const { name, message, stack }: { name: string, message: string, stack?: string } = err;
            context.error(`[FAILURE] Unexpected error has occured -> ${name}: ${message}`);

            if (stack) {
                context.trace(stack);
            }

            return {
                status: 500,
                body: `${name}: ${message}`
            };
        }
    } else {
        return {
            status: 400,
            body: `Webhook Error: Unhandled event type ${event.type}`
        }
    }
}

app.http('CompleteOrder', {
    methods: ['POST', "GET"],
    authLevel: 'anonymous',
    route: 'orders/complete',
    handler: CompleteOrder
});

function getCredentials(): any {
    var conn = {
        endpoint: process.env['cosmosDB__accountEndpoint']
    }

    if (process.env['cosmosDB__credential']) {
        conn['key'] = process.env['cosmosDB__credential']
    } else {
        conn['aadCredentials'] = new DefaultAzureCredential();
    }

    return conn;
}

package.json

{
  "name": "myapp",
  "version": "1.0.0",
  "description": "",
  "scripts": {
    "build": "tsc",
    "watch": "tsc -w",
    "clean": "rimraf dist",
    "prestart": "npm run clean && npm run build",
    "start": "func start",
    "test": "echo \"No tests yet...\""
  },
  "dependencies": {
    "@azure/cosmos": "^4.0.0",
    "@azure/functions": "^4.0.0",
    "@azure/identity": "^3.3.1",
    "@azure/storage-blob": "^12.16.0",
    "crypto": "^1.0.1",
    "joi": "^17.11.0",
    "stripe": "^13.10.0"
  },
  "devDependencies": {
    "@types/node": "^18.x",
    "rimraf": "^5.0.0",
    "typescript": "^4.0.0"
  },
  "main": "dist/src/functions/*.js"
}
@EnderGamingFilms EnderGamingFilms changed the title "No job functions found" - model v4 - TypeSrupt - Not recognizing existing functions "No job functions found" - model v4 - TypeScript - Not recognizing existing functions Oct 30, 2023
@ejizba
Copy link
Contributor

ejizba commented Oct 30, 2023

Hi @EnderGamingFilms can you make sure you have a local.settings.json file with FUNCTIONS_WORKER_RUNTIME set to node

@EnderGamingFilms
Copy link
Author

I can't believe I didn't notice that file was missing. Completely my bad 🤝

@johnnyreilly
Copy link

johnnyreilly commented Jan 14, 2024

For anyone searching the internet struggling - in my case I had to update my host.json to this:

{
    "version": "2.0",
    "logging": {
        "applicationInsights": {
            "samplingSettings": {
                "isEnabled": true,
                "excludedTypes": "Request"
            }
        }
    },
    "extensionBundle": {
        "id": "Microsoft.Azure.Functions.ExtensionBundle",
        "version": "[4.*, 5.0.0)"
    }
}

https://johnnyreilly.com/migrating-azure-functions-node-js-v4-typescript#3-running-locally

@ejizba
Copy link
Contributor

ejizba commented Jan 16, 2024

Hi @johnnyreilly cool blog post! Always nice to see real-life scenarios, as opposed to our official docs which are a bit more generic.

In terms of the host.json, I don't think you should need to update it to get local debugging to work. It depends what your host.json was before and what types of triggers you have in your app. If you want, feel free to file a new issue in the node.js repo and we can follow up: https://github.com/Azure/azure-functions-nodejs-library/issues/new

@johnnyreilly
Copy link

Hey @ejizba!

I'll try and reverse my change tomorrow and see if that does reliably break local debugging - if it does then I'll report back!

@johnnyreilly
Copy link

johnnyreilly commented Jan 17, 2024

So it's the weirdest thing. I spent literally hours being unable to run locally. I changed the host.json as suggested in https://johnnyreilly.com/migrating-azure-functions-node-js-v4-typescript#3-running-locally and I was able to run locally. I just tried changing it back locally and it still runs locally?! I cannot explain this!

I've updated the blog post to reference this discussion BTW

@ejizba
Copy link
Contributor

ejizba commented Jan 18, 2024

Haha I've been there. Just let us know if you ever get a repro of your old issue

@johnnyreilly
Copy link

Will do!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants