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

AppendBlob - how to update content type of leased append blob #25361

Closed
abhikt48 opened this issue Nov 12, 2021 · 3 comments
Closed

AppendBlob - how to update content type of leased append blob #25361

abhikt48 opened this issue Nov 12, 2021 · 3 comments
Assignees
Labels
Client This issue points to a problem in the data-plane of the library. customer-reported Issues that are reported by GitHub users external to the Azure organization. question The issue doesn't require a change to the product in order to be resolved. Most issues start as that Storage Storage Service (Queues, Blobs, Files)

Comments

@abhikt48
Copy link

abhikt48 commented Nov 12, 2021

We are using azure-storage-blob-12.10.2 to append blobs.

Requirement - Update content type of leased append blob

We found couple of limitation and issues while updating content type of append blob. We would appreciate any feedbacks on below limitations and issues. Please suggest best way to handle this issue.

Limitation

  1. BlobClient.uploadWithResponse have option to pass BlobHttpHeaders but AppendBlobClient.appendBlockWithResponse doesn't have this option.
    Can't we have same option with appendBlockWithResponse method?

  2. Performance - As updating content type is not an option in appendBlockWithResponse method, so we have to call AppendBlobClient.setHttpHeaders(..) which internally sends HTTP request again to update HTTPHeader.
    So we need to send request two time - First append blob and second update content type. As we are calling twice, so it could be performance barrier.
    Do we have any possibilities to merge both functionality into one operation?

  3. As per BlobClientBase.setHttpHeaders documentation - Changes a blob's HTTP header properties. if only one HTTP header is updated, the others will all be erased. In order to preserve existing values, they must be passed alongside the header being changed.
    With keeping above in mind,

  • We should have option getHtthHeaders, so we can preserve existing HtthHeaders and then update headers accordingly
  • Otherwise, we should have option to update only one header which should not wipe out other header
    Please suggest your thought on this.

Issue

  1. We are not able to update content type on lease blob. As there is no option to specify leaseID on BlobHttpHeaders, that's why we are getting LeaseIdMissing error. Please find below error stacktrace

Sample Code - AppendBlobLease

Error Logs

Exception in thread "main" com.azure.storage.blob.models.BlobStorageException: Status code 412, "<?xml version="1.0" encoding="utf-8"?><Error><Code>LeaseIdMissing</Code><Message>There is currently a lease on the blob and no lease ID was specified in the request.
RequestId:8***-00**-00**-29**-**
Time:2021-11-11T23:38:12.9914138Z</Message></Error>"
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
	at com.azure.core.http.rest.RestProxy.instantiateUnexpectedException(RestProxy.java:337)
	at com.azure.core.http.rest.RestProxy.lambda$ensureExpectedStatus$5(RestProxy.java:378)
	at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:118)
	at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1782)
	at reactor.core.publisher.MonoCacheTime$CoordinatorSubscriber.signalCached(MonoCacheTime.java:320)
	at reactor.core.publisher.MonoCacheTime$CoordinatorSubscriber.onNext(MonoCacheTime.java:337)
	at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2344)
	at reactor.core.publisher.MonoCacheTime$CoordinatorSubscriber.onSubscribe(MonoCacheTime.java:276)
	at reactor.core.publisher.FluxFlatMap.trySubscribeScalarMap(FluxFlatMap.java:191)
	at reactor.core.publisher.MonoFlatMap.subscribeOrReturn(MonoFlatMap.java:53)
	at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:57)
	at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52)
	at reactor.core.publisher.MonoCacheTime.subscribeOrReturn(MonoCacheTime.java:132)
	at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:57)
	at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:150)
	at reactor.core.publisher.FluxDoFinally$DoFinallySubscriber.onNext(FluxDoFinally.java:123)
	at reactor.core.publisher.FluxHandle$HandleSubscriber.onNext(FluxHandle.java:112)
	at reactor.core.publisher.FluxMap$MapConditionalSubscriber.onNext(FluxMap.java:213)
	at reactor.core.publisher.FluxDoFinally$DoFinallySubscriber.onNext(FluxDoFinally.java:123)
	at reactor.core.publisher.FluxHandleFuseable$HandleFuseableSubscriber.onNext(FluxHandleFuseable.java:178)
	at reactor.core.publisher.FluxContextStart$ContextStartSubscriber.onNext(FluxContextStart.java:96)
	at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1782)
	at reactor.core.publisher.MonoCollectList$MonoCollectListSubscriber.onComplete(MonoCollectList.java:121)
	at reactor.core.publisher.FluxPeek$PeekSubscriber.onComplete(FluxPeek.java:252)
	at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:136)
	at reactor.netty.channel.FluxReceive.onInboundComplete(FluxReceive.java:374)
	at reactor.netty.channel.ChannelOperations.onInboundComplete(ChannelOperations.java:373)
	at reactor.netty.channel.ChannelOperations.terminate(ChannelOperations.java:429)
	at reactor.netty.http.client.HttpClientOperations.onInboundNext(HttpClientOperations.java:655)
	at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:96)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436)
	at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:324)
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:296)
	at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1526)
	at io.netty.handler.ssl.SslHandler.decodeNonJdkCompatible(SslHandler.java:1287)
	at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1324)
	at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:501)
	at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:440)
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
	at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
	at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:714)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:650)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:576)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.lang.Thread.run(Thread.java:748)
	Suppressed: java.lang.Exception: #block terminated with an error
		at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:99)
		at reactor.core.publisher.Mono.block(Mono.java:1685)
		at com.azure.storage.common.implementation.StorageImplUtils.blockWithOptionalTimeout(StorageImplUtils.java:131)
		at com.azure.storage.blob.specialized.BlobClientBase.setHttpHeadersWithResponse(BlobClientBase.java:848)
		at com.azure.storage.blob.specialized.BlobClientBase.setHttpHeaders(BlobClientBase.java:823)
		at com.test.blob.AppendBlobLease.appendBlob(AppendBlobLease.java:76)
		at com.test.blob.AppendBlobLease.main(AppendBlobLease.java:51)

Setup (please complete the following information if applicable):
OS: window
IDE : eclipse based
Version of the Library used: azure-storage-blob-12.10.2

@ghost ghost added needs-triage Workflow: This is a new issue that needs to be triaged to the appropriate team. customer-reported Issues that are reported by GitHub users external to the Azure organization. question The issue doesn't require a change to the product in order to be resolved. Most issues start as that labels Nov 12, 2021
@abhikt48
Copy link
Author

HI All,
My issue has been resolved. I am able to update content type on leased blob with this operation setHttpHeadersWithResponse

However, i don't want to proceed further with this option because it will wipe out other header properties. So can you please provide your valuable input on above limitations.

Regards,
Abhishek Kumar

@rickle-msft
Copy link
Contributor

Hi, @abhikt48 sorry for the delay.

A couple thoughts that I think should help move you guys forward:

  • You can set the BlobHttpHeaders when call appendBlobClient.createWithResponse(...). You'll notice that blockBlobClient.stageBlock(...) does not accept http headers the same way appendBlobClient.appendBlock does not. This is because headers can be set when creating the blob but not when adding data to it.
  • You can pass the leaseId in any of the withResponse() methods. The leaseId will need to be set on the BlobRequestOptions
  • The semantics of setting http headers is actually defined by the service and not by the sdk, so we really won't be able to make any changes that will change the performance here. The service will continue to use replacement semantics instead of merge semantics, so we just have to work with that.

@rickle-msft rickle-msft self-assigned this Nov 15, 2021
@rickle-msft rickle-msft added Client This issue points to a problem in the data-plane of the library. Storage Storage Service (Queues, Blobs, Files) labels Nov 15, 2021
@ghost ghost removed the needs-triage Workflow: This is a new issue that needs to be triaged to the appropriate team. label Nov 15, 2021
@abhikt48
Copy link
Author

@rickle-msft Thanks for quick update..

@github-actions github-actions bot locked and limited conversation to collaborators Apr 11, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Client This issue points to a problem in the data-plane of the library. customer-reported Issues that are reported by GitHub users external to the Azure organization. question The issue doesn't require a change to the product in order to be resolved. Most issues start as that Storage Storage Service (Queues, Blobs, Files)
Projects
None yet
Development

No branches or pull requests

2 participants