Why I implemented a Serverless Function in COBOL.

Serverless Functions are usually associated with programming languages like JavaScript, Python, Go, or even plain old Java. But sometimes there is this one procedure, this one application that you need to run once or twice a week for recalculating those old contracts that would be a perfect fit for a cloud native, serverless implementation. But it was written in some legacy language like C. Or in OCAML. Or in COBOL.

For these cases, it might make sense to explore all the options you have with your serverless environment. In some cases, it is rather easy to use a custom runtime for that language you need, in some cases a little more effort is needed.

  • AWS. Lambda using a custom runtime.
  • Azure. Azure Functions provides a sophisticated and easy to work with environment, but sadly, it does not support custom runtimes. You are limited to a few languages — even Go is still missing. If you do not feel like contributing to Azure Functions source, the next best solution probably would be to use Azure Container Instances.
  • GCP. The premier way to run a custom Docker container seems to be Google App Engine Flexible, although you will have at least one instance run 24/7. If you can do this with Cloud Functions, then at least I wasn’t able to find out how.
  • OCI. As Oracle Functions are derived from fnproject, you can use some of their toolings for a highly customized runtime environment. All you need to do is prepare a Dockerfile containing your runtime and code and use the hotwrap binary as a wrapper to fulfill the fnproject runtime contract.

Due to my background, I will explore the last option, so running COBOL code in an Oracle Function. I already wrote a few posts on Oracle Functions — in case you are new to this topic the posts on environment setup and writing a first function are a good starting point.

Hello, COBOL!

I have to admit I do not really know COBOL. With some guides and tutorials, I finally managed to write a simple hello world program, that actually would compile and run. And here’s the code.

*******> Sample for running COBOL code with fn
IDENTIFICATION DIVISION.
PROGRAM-ID. FN_COB.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT SYSIN ASSIGN TO KEYBOARD ORGANIZATION LINE SEQUENTIAL.
DATA DIVISION.
FILE SECTION.
FD SYSIN.
01 LN PIC X(80).
88 EOF VALUE HIGH-VALUES.
WORKING-STORAGE SECTION.
01 WS-STDIN GLOBAL PIC X(255).
01 W-IDX PIC 9(2) VALUE ZERO.
PROCEDURE DIVISION.
ACCEPT WS-STDIN.
UNSTRING WS-STDIN DELIMITED ALL SPACE
INTO WS-STDIN COUNT W-IDX
IF W-IDX > 0 THEN
DISPLAY "Hello, " WS-STDIN(1:W-IDX) "!"
ELSE
DISPLAY "Hello, World!"
END-IF
STOP RUN.

If you pass input on STDIN, it will return a friendly Hello and echo the input. If there is no input, it will just say “Hello, World!”.

For tinkering around I used the GNU COBOL implementation. It seems to be a great starting place to get an idea of how COBOL works and seems to be working well with some of the existing code coming from other platforms and compilers.

Defining the Runtime

Since we now got the COBOL “application”, it is time to prepare the runtime. All we need is a Docker image based on Alpine Linux, a COBOL build and runtime environment, and the fnproject hotwrap binary.

FROM alpine:latest

WORKDIR /opt

RUN apk add tar libaio libnsl libc6-compat autoconf make g++ gmp-dev db-dev libxml2-dev

# get cJSON
RUN wget https://github.com/DaveGamble/cJSON/archive/v1.7.14.tar.gz && tar xvfz v1.7.14.tar.gz && \
cd cJSON-1.7.14 && make && make install && cd ..

# get and install gnucobol
RUN wget https://sourceforge.net/projects/gnucobol/files/gnucobol/3.1/gnucobol-3.1-rc1.tar.gz/download -O gnucobol-3.1-rc1.tar.gz && \
tar xvfz gnucobol-3.1-rc1.tar.gz && cd gnucobol-3.1-rc1 && ./configure && make && make install && cd ..

# get fn hotwrap
COPY --from=fnproject/hotwrap:latest /hotwrap /hotwrap

COPY ./src .
RUN cobc -x func.cob

CMD ./func
ENTRYPOINT ["/hotwrap"]

Please note that GNU COBOL is built here with XML and JSON support. So for making real-life functions this might be a sensible starting point. Just think of splitting up the image in a build and a run part to get down to a sensible size then.

After building and deploying the function, a simple test shows that everything works as expected. Serverless COBOL!

Apart from sounding funny, does this really make any sense?

I think this proof of concept does make sense. If you got some function that is stateless and does not need more than 300 seconds of execution time, then it is a candidate for a serverless function. And if you find that you need some very special runtime environment components that you would run in a Docker container, then it is a candidate for a custom runtime as described in this post. Just keep in mind: If trying to use proprietary runtimes, make sure to understand the licensing terms.

COBOL might be just an example of a rather uncommon runtime in today's cloud environments, but there for sure is a lot of custom code written in C, C++, Perl or Fortran. This approach might help to remove one component of your landscape that is needed just to run that code. You might have a hard time if trying to run RGP code though;)

Originally published at https://blog.maxjahn.at on November 12, 2020.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store