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

Table Storage Binding doesn't allow for access or filtering of Table Storage 'Timestamp' property #320

Open
SKHolmes opened this issue Jul 16, 2020 · 2 comments

Comments

@SKHolmes
Copy link

Investigative information

Upon retrieving the whole table via my bindings in a function that is triggered on a timer, (see below).

{
  "bindings": [
    {
      "name": "myTimer",
      "type": "timerTrigger",
      "direction": "in",
      "schedule": "0 */1 * * * *"
    },
    {
      "name": "eventTable",
      "type": "table",
      "tableName": "HeartbeatEvents",
      "direction": "in"
    }
  ],
  "scriptFile": "../dist/src/heartbeat-scheduler/index.js"
}

I would expect that the property Timestamp which is a property maintained by the Storage Table server is included in the eventTable binding in the code and be accessible as a property of the array elements of the eventTable, i.e

context.bindings.eventTable.forEach((row) => {
    context.log(row.Timestamp);
  });

Instead it is undefined.

In the case of the storage table I am using a very basic set up like so,
image

And when I run the function locally, it is not deployed yet, I get the following output through context logging,

[16/07/2020 1:51:00 am] Executing 'Functions.heartbeat-scheduler' (Reason='Timer fired at 2020-07-16T13:51:00.0093734+12:00', Id=9972164a-5a33-4f68-a240-95e6b7b6db20)
[16/07/2020 1:51:00 am] Heartbeat Logging Triggered on: Thu Jul 16 2020 13:51:00 GMT+1200
[16/07/2020 1:51:00 am] [
{
Status: 'received',
TransactionId: '40574c28-0478-4aeb-a568-40cfea7b957c',
PartitionKey: 'com.triquestra.cloudevents.salesinvoices.heartbeat',
RowKey: 'tq-site_code-101'
},
{
Status: 'received',
TransactionId: '50574c28-0478-4aeb-a568-40cfea7b957c',
PartitionKey: 'com.triquestra.cloudevents.salesinvoices.heartbeat',
RowKey: 'tq-site_code-102'
}
]
[16/07/2020 1:51:00 am] Row 0 has timestamp of: undefined
[16/07/2020 1:51:00 am] Row 0 has new heartbeat
[16/07/2020 1:51:00 am] Row 1 has timestamp of: undefined
[16/07/2020 1:51:00 am] Row 1 has new heartbeat
[16/07/2020 1:51:00 am] Executed 'Functions.heartbeat-scheduler' (Succeeded, Id=9972164a-5a33-4f68-a240-95e6b7b6db20)
Note how Timestamp is excluded.

As this function is only local at the moment I do not have any function id information yet.

Reproduction steps

  1. Create a storage table and insert a record (Note that the timestamp field is automatically created and updated)
  2. Create a basic timer-triggered application. (This application was built off the example provided here.)
  3. Link the storage account associated with the table in your local settings.
  4. Try to access the table row's in the timerTrigger function and see that Timestamp is inaccessible.

Expected behavior

Expected that Timestamp is accessible for use in the function code.

Actual behavior

Any attempts to access Timestamp returns undefined.

Known workarounds

None known so far. Although I did try adding a filter to the binding to limit by Timestamp and it throws an error. (Accessing other valid properties within the table were fine.)

Related information

The function was built in typescript with the only dependency being moment.js. The source for the function is copied below for fast reproduction of the issue.

Source
import { AzureFunction, Context } from '@azure/functions';
import moment from 'moment';
import { triggerStartMessage } from '../resources/constants';

const timerTrigger: AzureFunction = async function (
  context: Context,
  myTimer: any
): Promise<void> {
  const now = moment();
  const timeStamp = now.toString();
  const fifteenMinutesAgo = now.subtract(15, 'minutes');

  context.log(triggerStartMessage(timeStamp));
  context.log(context.bindings.eventTable);

  const checkHeartbeat = (row, index) => {
    const isOldHeartbeat = fifteenMinutesAgo.isAfter(row.Timestamp);
    context.log(`Row ${index} has timestamp of: ${row.Timestamp}`);
    if (isOldHeartbeat) {
      context.log(`Row ${index} has old heartbeat`);
    } else {
      context.log(`Row ${index} has new heartbeat`);
    }
  }

  context.bindings.eventTable.map(checkHeartbeat);
};

export default timerTrigger;
@mikkark
Copy link

mikkark commented May 18, 2021

I just bumped into this myself too. I thought about doing my custom backup solution for some data in Table Storage using a simple timed Azure Function in TS, but I will miss the timestamp field. It is not exactly a showstopper for me, but very strange indeed.

@alrod
Copy link
Member

alrod commented Jan 14, 2022

I was able to reproduce the issue in Javascript as well as in Python.
Probably it's related to Timestamp protopbuf type and it's truncated somehow during sending grpc messge from function host to language worker.

DateTime property with another name works fine.

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

No branches or pull requests

4 participants