question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Allow for calling custom code before and after function execution

See original GitHub issue

I have been struggling to come up with a clean way to run code before and after a function runs, and I feel that it would be a worthwhile feature to add as it would promote modular, reusable code.

My specific use-case is to wrap my function invocation in a database transaction. Currently, I have to place a await UnitOfWork.SaveChangesAsync(); at the bottom of each function. I would like to streamline this by simply placing a attribute on my function.

A second use-case is to make it easier to implement benchmarking or telemetry such as Application Insights, as it would be very convenient to use DI to inject a telemetry tool, start a stop watch prior to function invocation, and then send it up after the fact.

Right now I can’t find a existing extensibility point for functions. The IJobActivator interface lets me create the class, but has no knowledge of the function being executed.

Custom processors have before / after methods, but again do not have any knowledge of the actual function being executed. Additionally, the instances have already been disposed of at this point.

To solve this issue, I would propose adding a interface that defines before / after functionality. In my proof of concept, I built it out like this:

    /// <summary>
    /// Interface defining functionality for executing code before and after function invocation.
    /// </summary>
    public interface IExtendableFunction
    {
        /// <summary>
        /// Executes before function invocation.
        /// </summary>
        /// <param name="info">The <see cref="MethodInfo"/> for the function invocation.</param>
        /// <param name="arguments">The list of arguments passed to the function.</param>
        /// <returns>A <see cref="Task"/> for the operation.</returns>
        Task BeforeFunctionExecutionAsync(MethodInfo info, object[] arguments);

        /// <summary>
        /// Executes after function invocation.
        /// </summary>
        /// <param name="info">The <see cref="MethodInfo"/> for the function invocation.</param>
        /// <param name="arguments">The list of arguments passed to the function.</param>
        /// <returns>A <see cref="Task"/> for the operation.</returns>
        Task AfterFunctionExecutionAsync(MethodInfo info, object[] arguments);
    }

Then, a simple tweak to FunctionInvoker<TReflected>:

  • Adding a private readonly MethodInfo to the class and instanciating it from the constructor
  • Updating InvokeAsync:
        public async Task InvokeAsync(object[] arguments)
        {
            // Return a task immediately in case the method is not async.
            await Task.Yield();

            TReflected instance = _instanceFactory.Create();

            using (instance as IDisposable)
            {
                if (instance is IExtendableFunction)
                {
                    await((IExtendableFunction)instance).BeforeFunctionExecutionAsync(_methodInfo, arguments);
                }

                await _methodInvoker.InvokeAsync(instance, arguments);

                if (instance is IExtendableFunction)
                {
                    await((IExtendableFunction)instance).AfterFunctionExecutionAsync(_methodInfo, arguments);
                }
            }
        }

If you are willing to add this functionality, I would be more than happy to submit a pull request with my changes.

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Reactions:1
  • Comments:9 (4 by maintainers)

github_iconTop GitHub Comments

3reactions
dfaivrecommented, Mar 21, 2017

This would also make my life easier (though I may just not have a deep enough understanding of the WebJobs SDK yet). I’d like my functions invoked with DI with a scope of each invocation. I’d also like to to be able to add “job context information” to our Serilog infrastructure.

2reactions
Bio2hazardcommented, Jul 13, 2017

That works beautifully, and even flows nicely through inherited classes. 👍

Thank you so much. Excited to see it in a release in the near future.

Read more comments on GitHub >

github_iconTop Results From Across the Web

execute some code before and after of any method ...
I want to print values from annotation without using System.out.println() in main method . when I just call sayHello() method . annotation ...
Read more >
Injecting Behaviors Before and After Method Execution
Executing code before and after method execution ... derives from the Attribute class, you can just add the aspect custom attribute to the...
Read more >
Custom code workflow actions
In workflows, use the Custom code action to write and execute JavaScript or ... action with Python, click the Language dropdown menu, then...
Read more >
JavaScript Callback Functions – What are Callbacks in JS ...
In JavaScript, the way to create a callback function is to pass it as a parameter to another function, and then to call...
Read more >
Custom code and assembly references in expressions in a ...
To use custom assemblies in a report, you must first create the assembly, make it available to Report Designer, add a reference to...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found